How to determine the transparent color index of an ICO image using PIL?

In particular, this is from the .ico file, so there is no "transparent" attribute "info", as you would get in the gif. The example below shows the conversion of Yahoo! favicon to png using the correct transparency index β€œ0”, which I guessed. how to detect that ico is really transparent and that the transparency index is 0?

import urllib2 import Image import StringIO resp = urllib2.urlopen("http://www.yahoo.com/favicon.ico") image = Image.open(StringIO.StringIO(resp.read())) f = file("test.png", "w") # I guessed that the transparent index is 0. how to # determine it correctly ? image.save(f, "PNG", quality=95, transparency=0) 
+4
source share
1 answer

it looks like someone found out that PIL really does not read the ICO correctly (I see the same after matching its source code with some studies in the ICO format - there is the AND bit, which defines transparency) and came up with this extension:

http://www.djangosnippets.org/snippets/1287/

since this is useful for applications other than django, I have reworked several modifications here to exclude it:

 import operator import struct from PIL import BmpImagePlugin, PngImagePlugin, Image def load_icon(file, index=None): ''' Load Windows ICO image. See http://en.wikipedia.org/w/index.php?oldid=264332061 for file format description. ''' if isinstance(file, basestring): file = open(file, 'rb') try: header = struct.unpack('<3H', file.read(6)) except: raise IOError('Not an ICO file') # Check magic if header[:2] != (0, 1): raise IOError('Not an ICO file') # Collect icon directories directories = [] for i in xrange(header[2]): directory = list(struct.unpack('<4B2H2I', file.read(16))) for j in xrange(3): if not directory[j]: directory[j] = 256 directories.append(directory) if index is None: # Select best icon directory = max(directories, key=operator.itemgetter(slice(0, 3))) else: directory = directories[index] # Seek to the bitmap data file.seek(directory[7]) prefix = file.read(16) file.seek(-16, 1) if PngImagePlugin._accept(prefix): # Windows Vista icon with PNG inside image = PngImagePlugin.PngImageFile(file) else: # Load XOR bitmap image = BmpImagePlugin.DibImageFile(file) if image.mode == 'RGBA': # Windows XP 32-bit color depth icon without AND bitmap pass else: # Patch up the bitmap height image.size = image.size[0], image.size[1] >> 1 d, e, o, a = image.tile[0] image.tile[0] = d, (0, 0) + image.size, o, a # Calculate AND bitmap dimensions. See # http://en.wikipedia.org/w/index.php?oldid=264236948#Pixel_storage # for description offset = o + a[1] * image.size[1] stride = ((image.size[0] + 31) >> 5) << 2 size = stride * image.size[1] # Load AND bitmap file.seek(offset) string = file.read(size) mask = Image.fromstring('1', image.size, string, 'raw', ('1;I', stride, -1)) image = image.convert('RGBA') image.putalpha(mask) return image 
+5
source

Source: https://habr.com/ru/post/1286147/


All Articles