def chunk_PLTE(self, pos, len): # palette s = ImageFile._safe_read(self.fp, len) if self.im_mode == "P": self.im_palette = "RGB", s return s
def SOF(self, marker): # # Start of frame marker. Defines the size and mode of the # image. JPEG is colour blind, so we use some simple # heuristics to map the number of layers to an appropriate # mode. Note that this could be made a bit brighter, by # looking for JFIF and Adobe APP markers. n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) self.size = i16(s[3:]), i16(s[1:]) self.bits = ord(s[0]) if self.bits != 8: raise SyntaxError("cannot handle %d-bit layers" % self.bits) self.layers = ord(s[5]) if self.layers == 1: self.mode = "L" elif self.layers == 3: self.mode = "RGB" elif self.layers == 4: self.mode = "CMYK" else: raise SyntaxError("cannot handle %d-layer images" % self.layers) if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]: self.info["progression"] = 1 for i in range(6, len(s), 3): t = s[i:i + 3] # 4-tuples: id, vsamp, hsamp, qtable self.layer.append((t[0], ord(t[1]) / 16, ord(t[1]) & 15, ord(t[2])))
def SOF(self, marker): # # Start of frame marker. Defines the size and mode of the # image. JPEG is colour blind, so we use some simple # heuristics to map the number of layers to an appropriate # mode. Note that this could be made a bit brighter, by # looking for JFIF and Adobe APP markers. n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) self.size = i16(s[3:]), i16(s[1:]) self.bits = ord(s[0]) if self.bits != 8: raise SyntaxError("cannot handle %d-bit layers" % self.bits) self.layers = ord(s[5]) if self.layers == 1: self.mode = "L" elif self.layers == 3: self.mode = "RGB" elif self.layers == 4: self.mode = "CMYK" else: raise SyntaxError("cannot handle %d-layer images" % self.layers) if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]: self.info["progression"] = 1 for i in range(6, len(s), 3): t = s[i:i+3] # 4-tuples: id, vsamp, hsamp, qtable self.layer.append((t[0], ord(t[1])/16, ord(t[1])&15, ord(t[2])))
def COM(self, marker): # # Comment marker. Store these in the APP dictionary. n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) self.app["COM"] = s # compatibility self.applist.append(("COM", s))
def COM(self, marker): # # Comment marker. Store these in the APP dictionary. n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) self.app["COM"] = s # compatibility self.applist.append(("COM", s))
def APP(self, marker): # # Application marker. Store these in the APP dictionary. # Also look for well-known application markers. n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) app = "APP%d" % (marker & 15) self.app[app] = s # compatibility self.applist.append((app, s)) if marker == 0xFFE0 and s[:4] == "JFIF": # extract JFIF information self.info["jfif"] = version = i16(s, 5) # version self.info["jfif_version"] = divmod(version, 256) # extract JFIF properties try: jfif_unit = ord(s[7]) jfif_density = i16(s, 8), i16(s, 10) except: pass else: if jfif_unit == 1: self.info["dpi"] = jfif_density self.info["jfif_unit"] = jfif_unit self.info["jfif_density"] = jfif_density elif marker == 0xFFE1 and s[:5] == "Exif\0": # extract Exif information (incomplete) self.info["exif"] = s # FIXME: value will change elif marker == 0xFFE2 and s[:5] == "FPXR\0": # extract FlashPix information (incomplete) self.info["flashpix"] = s # FIXME: value will change elif marker == 0xFFE2 and s[:12] == "ICC_PROFILE\0": # Since an ICC profile can be larger than the maximum size of # a JPEG marker (64K), we need provisions to split it into # multiple markers. The format defined by the ICC specifies # one or more APP2 markers containing the following data: # Identifying string ASCII "ICC_PROFILE\0" (12 bytes) # Marker sequence number 1, 2, etc (1 byte) # Number of markers Total of APP2's used (1 byte) # Profile data (remainder of APP2 data) # Decoders should use the marker sequence numbers to # reassemble the profile, rather than assuming that the APP2 # markers appear in the correct sequence. self.icclist.append(s) elif marker == 0xFFEE and s[:5] == "Adobe": self.info["adobe"] = i16(s, 5) # extract Adobe custom properties try: adobe_transform = ord(s[1]) except: pass else: self.info["adobe_transform"] = adobe_transform
def APP(self, marker): # # Application marker. Store these in the APP dictionary. # Also look for well-known application markers. n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) app = "APP%d" % (marker&15) self.app[app] = s # compatibility self.applist.append((app, s)) if marker == 0xFFE0 and s[:4] == "JFIF": # extract JFIF information self.info["jfif"] = version = i16(s, 5) # version self.info["jfif_version"] = divmod(version, 256) # extract JFIF properties try: jfif_unit = ord(s[7]) jfif_density = i16(s, 8), i16(s, 10) except: pass else: if jfif_unit == 1: self.info["dpi"] = jfif_density self.info["jfif_unit"] = jfif_unit self.info["jfif_density"] = jfif_density elif marker == 0xFFE1 and s[:5] == "Exif\0": # extract Exif information (incomplete) self.info["exif"] = s # FIXME: value will change elif marker == 0xFFE2 and s[:5] == "FPXR\0": # extract FlashPix information (incomplete) self.info["flashpix"] = s # FIXME: value will change elif marker == 0xFFE2 and s[:12] == "ICC_PROFILE\0": # Since an ICC profile can be larger than the maximum size of # a JPEG marker (64K), we need provisions to split it into # multiple markers. The format defined by the ICC specifies # one or more APP2 markers containing the following data: # Identifying string ASCII "ICC_PROFILE\0" (12 bytes) # Marker sequence number 1, 2, etc (1 byte) # Number of markers Total of APP2's used (1 byte) # Profile data (remainder of APP2 data) # Decoders should use the marker sequence numbers to # reassemble the profile, rather than assuming that the APP2 # markers appear in the correct sequence. self.icclist.append(s) elif marker == 0xFFEE and s[:5] == "Adobe": self.info["adobe"] = i16(s, 5) # extract Adobe custom properties try: adobe_transform = ord(s[1]) except: pass else: self.info["adobe_transform"] = adobe_transform
def load(self, fp): # load tag dictionary self.reset() i16 = self.i16 i32 = self.i32 for i in range(i16(fp.read(2))): ifd = fp.read(12) tag, typ = i16(ifd), i16(ifd, 2) if Image.DEBUG: import TiffTags tagname = TiffTags.TAGS.get(tag, "unknown") typname = TiffTags.TYPES.get(typ, "unknown") print "tag: %s (%d)" % (tagname, tag), print "- type: %s (%d)" % (typname, typ), try: dispatch = self.load_dispatch[typ] except KeyError: if Image.DEBUG: print "- unsupported type", typ continue # ignore unsupported type size, handler = dispatch size = size * i32(ifd, 4) # Get and expand tag value if size > 4: here = fp.tell() fp.seek(i32(ifd, 8)) data = ImageFile._safe_read(fp, size) fp.seek(here) else: data = ifd[8:8 + size] if len(data) != size: raise IOError, "not enough data" self.tagdata[tag] = typ, data self.tagtype[tag] = typ if Image.DEBUG: if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP): print "- value: <table: %d bytes>" % size else: print "- value:", self[tag] self.next = i32(fp.read(4))
def load(self, fp): # load tag dictionary self.reset() i16 = self.i16 i32 = self.i32 for i in range(i16(fp.read(2))): ifd = fp.read(12) tag, typ = i16(ifd), i16(ifd, 2) if Image.DEBUG: import TiffTags tagname = TiffTags.TAGS.get(tag, "unknown") typname = TiffTags.TYPES.get(typ, "unknown") print "tag: %s (%d)" % (tagname, tag), print "- type: %s (%d)" % (typname, typ), try: dispatch = self.load_dispatch[typ] except KeyError: if Image.DEBUG: print "- unsupported type", typ continue # ignore unsupported type size, handler = dispatch size = size * i32(ifd, 4) # Get and expand tag value if size > 4: here = fp.tell() fp.seek(i32(ifd, 8)) data = ImageFile._safe_read(fp, size) fp.seek(here) else: data = ifd[8 : 8 + size] if len(data) != size: raise IOError, "not enough data" self.tagdata[tag] = typ, data self.tagtype[tag] = typ if Image.DEBUG: if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP): print "- value: <table: %d bytes>" % size else: print "- value:", self[tag] self.next = i32(fp.read(4))
def chunk_tEXt(self, pos, len): # text s = ImageFile._safe_read(self.fp, len) try: k, v = string.split(s, "\0", 1) except ValueError: k = s; v = "" # fallback for broken tEXt tags if k: self.im_info[k] = self.im_text[k] = v return s
def chunk_zTXt(self, pos, len): # compressed text s = ImageFile._safe_read(self.fp, len) k, v = string.split(s, "\0", 1) comp_method = ord(v[0]) if comp_method != 0: raise SyntaxError("Unknown compression method %s in zTXt chunk" % comp_method) import zlib self.im_info[k] = self.im_text[k] = zlib.decompress(v[1:]) return s
def chunk_tRNS(self, pos, len): # transparency s = ImageFile._safe_read(self.fp, len) if self.im_mode == "P": i = string.find(s, chr(0)) if i >= 0: self.im_info["transparency"] = i elif self.im_mode == "L": self.im_info["transparency"] = i16(s) return s
def chunk_zTXt(self, pos, len): s = ImageFile._safe_read(self.fp, len) (k, v) = string.split(s, "\0", 1) comp_method = ord(v[0]) v = v[1:] if comp_method != 0: raise SyntaxError, "Unknown compression method %i in zTXt chunk" % comp_method import zlib v = zlib.decompress(v) self.im_info[k] = v return s
def chunk_pHYs(self, pos, len): # pixels per unit s = ImageFile._safe_read(self.fp, len) px, py = i32(s), i32(s[4:]) unit = ord(s[8]) if unit == 1: # meter dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5) self.im_info["dpi"] = dpi elif unit == 0: self.im_info["aspect"] = px, py return s
def chunk_tRNS(self, pos, len): # transparency s = ImageFile._safe_read(self.fp, len) if self.im_mode == "P": i = s.find(b'\x00') if i >= 0: self.im_info["transparency"] = i elif self.im_mode == "L": self.im_info["transparency"] = i16(s) elif self.im_mode == "RGB": self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:]) return s
def chunk_zTXt(self, pos, len): # compressed text s = ImageFile._safe_read(self.fp, len) k, v = s.split(b"\x00", 1) comp_method = v[0] if comp_method != 0: raise SyntaxError("Unknown compression method {0} in zTXt " "chunk".format(comp_method)) import zlib self.im_info[k] = self.im_text[k] = zlib.decompress(v[1:]) return s
def chunk_IHDR(self, pos, len): # image header s = ImageFile._safe_read(self.fp, len) self.im_size = i32(s), i32(s[4:]) try: self.im_mode, self.im_rawmode = _MODES[(ord(s[8]), ord(s[9]))] except: pass if ord(s[12]): self.im_info["interlace"] = 1 if ord(s[11]): raise SyntaxError, "unknown filter category" return s
def chunk_tRNS(self, pos, len): # transparency s = ImageFile._safe_read(self.fp, len) if self.im_mode == "P": #i = string.find(s, chr(0)) #if i >= 0: # self.im_info["transparency"] = i self.im_info["transparency"] = s elif self.im_mode == "L": self.im_info["transparency"] = i16(s) elif self.im_mode == "RGB": self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:]) return s
def verify(self, endchunk = "IEND"): # Simple approach; just calculate checksum for all remaining # blocks. Must be called directly after open. cids = [] while 1: cid, pos, len = self.read() if cid == endchunk: break self.crc(cid, ImageFile._safe_read(self.fp, len)) cids.append(cid) return cids
def verify(self, endchunk="IEND"): # Simple approach; just calculate checksum for all remaining # blocks. Must be called directly after open. cids = [] while 1: cid, pos, len = self.read() if cid == endchunk: break self.crc(cid, ImageFile._safe_read(self.fp, len)) cids.append(cid) return cids
def SOF(self, marker): # # Start of frame marker. Defines the size and mode of the # image. JPEG is colour blind, so we use some simple # heuristics to map the number of layers to an appropriate # mode. Note that this could be made a bit brighter, by # looking for JFIF and Adobe APP markers. n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) self.size = i16(s[3:]), i16(s[1:]) self.bits = s[0] if self.bits != 8: raise SyntaxError("cannot handle {0}-bit layers".format(self.bits)) self.layers = s[5] if self.layers == 1: self.mode = "L" elif self.layers == 3: self.mode = "RGB" elif self.layers == 4: self.mode = "CMYK" else: raise SyntaxError("cannot handle {0}-layer images".format(self.layers)) if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]: self.info["progressive"] = self.info["progression"] = 1 if self.icclist: # fixup icc profile self.icclist.sort() # sort by sequence number #if ord(self.icclist[0][13]) == len(self.icclist): if self.icclist[0][13] == len(self.icclist): profile = [] for p in self.icclist: profile.append(p[14:]) icc_profile = b''.join(profile) else: icc_profile = None # wrong number of fragments self.info["icc_profile"] = icc_profile self.icclist = None for i in range(6, len(s), 3): t = s[i:i+3] # 4-tuples: id, vsamp, hsamp, qtable #self.layer.append((t[0], ord(t[1])//16, ord(t[1])&15, ord(t[2]))) self.layer.append((bytes((t[0],)), t[1]//16, t[1]&15, t[2]))
def SOF(self, marker): # # Start of frame marker. Defines the size and mode of the # image. JPEG is colour blind, so we use some simple # heuristics to map the number of layers to an appropriate # mode. Note that this could be made a bit brighter, by # looking for JFIF and Adobe APP markers. n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) self.size = i16(s[3:]), i16(s[1:]) self.bits = ord(s[0]) if self.bits != 8: raise SyntaxError("cannot handle %d-bit layers" % self.bits) self.layers = ord(s[5]) if self.layers == 1: self.mode = "L" elif self.layers == 3: self.mode = "RGB" elif self.layers == 4: self.mode = "CMYK" else: raise SyntaxError("cannot handle %d-layer images" % self.layers) if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]: self.info["progressive"] = self.info["progression"] = 1 if self.icclist: # fixup icc profile self.icclist.sort() # sort by sequence number if ord(self.icclist[0][13]) == len(self.icclist): profile = [] for p in self.icclist: profile.append(p[14:]) icc_profile = string.join(profile, "") else: icc_profile = None # wrong number of fragments self.info["icc_profile"] = icc_profile self.icclist = None for i in range(6, len(s), 3): t = s[i:i + 3] # 4-tuples: id, vsamp, hsamp, qtable self.layer.append((t[0], ord(t[1]) / 16, ord(t[1]) & 15, ord(t[2])))
def _open(self): if self.fp.read(8) != _MAGIC: raise SyntaxError, "not a PNG file" # # Parse headers up to the first IDAT chunk self.png = PngStream(self.fp) while 1: # # get next chunk cid, pos, len = self.png.read() try: s = self.png.call(cid, pos, len) except EOFError: break except AttributeError: if Image.DEBUG: print cid, pos, len, "(unknown)" s = ImageFile._safe_read(self.fp, len) self.png.crc(cid, s) # # Copy relevant attributes from the PngStream. An alternative # would be to let the PngStream class modify these attributes # directly, but that introduces circular references which are # difficult to break if things go wrong in the decoder... # (believe me, I've tried ;-) self.mode = self.png.im_mode self.size = self.png.im_size self.info = self.png.im_info self.text = self.png.im_text # experimental self.tile = self.png.im_tile if self.png.im_palette: rawmode, data = self.png.im_palette self.palette = ImagePalette.raw(rawmode, data) self.__idat = len # used by load_read()
def DQT(self, marker): # # Define quantization table. Support baseline 8-bit tables # only. Note that there might be more than one table in # each marker. n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) while len(s): if len(s) < 65: raise SyntaxError("bad quantization table marker") v = ord(s[0]) if v/16 == 0: self.quantization[v&15] = array.array("b", s[1:65]) s = s[65:] else: return
def APP(self, marker): # # Application marker. Store these in the APP dictionary. # Also look for well-known application markers. n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) app = "APP%d" % (marker&15) self.app[app] = s # compatibility self.applist.append((app, s)) if marker == 0xFFE0 and s[:4] == "JFIF": # extract JFIF information self.info["jfif"] = version = i16(s, 5) # version self.info["jfif_version"] = divmod(version, 256) # extract JFIF properties try: jfif_unit = ord(s[7]) jfif_density = i16(s, 8), i16(s, 10) except: pass else: if jfif_unit == 1: self.info["dpi"] = jfif_density self.info["jfif_unit"] = jfif_unit self.info["jfif_density"] = jfif_density elif marker == 0xFFE1 and s[:5] == "Exif\0": # extract Exif information (incomplete) self.info["exif"] = s # FIXME: value will change elif marker == 0xFFE2 and s[:5] == "FPXR\0": # extract FlashPix information (incomplete) self.info["flashpix"] = s # FIXME: value will change elif marker == 0xFFEE and s[:5] == "Adobe": self.info["adobe"] = i16(s, 5) # extract Adobe custom properties try: adobe_transform = ord(s[1]) except: pass else: self.info["adobe_transform"] = adobe_transform
def APP(self, marker): # # Application marker. Store these in the APP dictionary. # Also look for well-known application markers. n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) app = "APP%d" % (marker & 15) self.app[app] = s # compatibility self.applist.append((app, s)) if marker == 0xFFE0 and s[:4] == "JFIF": # extract JFIF information self.info["jfif"] = version = i16(s, 5) # version self.info["jfif_version"] = divmod(version, 256) # extract JFIF properties try: jfif_unit = ord(s[7]) jfif_density = i16(s, 8), i16(s, 10) except: pass else: if jfif_unit == 1: self.info["dpi"] = jfif_density self.info["jfif_unit"] = jfif_unit self.info["jfif_density"] = jfif_density elif marker == 0xFFE1 and s[:5] == "Exif\0": # extract Exif information (incomplete) self.info["exif"] = s # FIXME: value will change elif marker == 0xFFE2 and s[:5] == "FPXR\0": # extract FlashPix information (incomplete) self.info["flashpix"] = s # FIXME: value will change elif marker == 0xFFEE and s[:5] == "Adobe": self.info["adobe"] = i16(s, 5) # extract Adobe custom properties try: adobe_transform = ord(s[1]) except: pass else: self.info["adobe_transform"] = adobe_transform
def DQT(self, marker): # # Define quantization table. Support baseline 8-bit tables # only. Note that there might be more than one table in # each marker. # FIXME: The quantization tables can be used to estimate the # compression quality. n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) while len(s): if len(s) < 65: raise SyntaxError("bad quantization table marker") v = ord(s[0]) if v / 16 == 0: self.quantization[v & 15] = array.array("b", s[1:65]) s = s[65:] else: return # FIXME: add code to read 16-bit tables!
def DQT(self, marker): # # Define quantization table. Support baseline 8-bit tables # only. Note that there might be more than one table in # each marker. # FIXME: The quantization tables can be used to estimate the # compression quality. n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) while len(s): if len(s) < 65: raise SyntaxError("bad quantization table marker") v = s[0] if v//16 == 0: self.quantization[v&15] = array.array("b", s[1:65]) s = s[65:] else: return # FIXME: add code to read 16-bit tables!
def chunk_iCCP(self, pos, len): # ICC profile s = ImageFile._safe_read(self.fp, len) # according to PNG spec, the iCCP chunk contains: # Profile name 1-79 bytes (character string) # Null separator 1 byte (null character) # Compression method 1 byte (0) # Compressed profile n bytes (zlib with deflate compression) i = string.find(s, chr(0)) if Image.DEBUG: print "iCCP profile name", s[:i] print "Compression method", ord(s[i]) comp_method = ord(s[i]) if comp_method != 0: raise SyntaxError("Unknown compression method %s in iCCP chunk" % comp_method) try: icc_profile = zlib.decompress(s[i+2:]) except zlib.error: icc_profile = None # FIXME self.im_info["icc_profile"] = icc_profile return s
def Skip(self, marker): n = i16(self.fp.read(2))-2 ImageFile._safe_read(self.fp, n)
def _bitmap(self, header=0, offset=0): if header: self.fp.seek(header) read = self.fp.read # CORE/INFO s = read(4) s = s + ImageFile._safe_read(self.fp, i32(s) - 4) if len(s) == 12: # OS/2 1.0 CORE bits = i16(s[10:]) self.size = i16(s[4:]), i16(s[6:]) compression = 0 lutsize = 3 colors = 0 direction = -1 elif len(s) in [40, 64]: # WIN 3.1 or OS/2 2.0 INFO bits = i16(s[14:]) self.size = i32(s[4:]), i32(s[8:]) compression = i32(s[16:]) lutsize = 4 colors = i32(s[32:]) direction = -1 if s[11] == '\xff': # upside-down storage self.size = self.size[0], 2**32 - self.size[1] direction = 0 else: raise IOError("Unsupported BMP header type (%d)" % len(s)) if not colors: colors = 1 << bits # MODE try: self.mode, rawmode = BIT2MODE[bits] except KeyError: raise IOError("Unsupported BMP pixel depth (%d)" % bits) if compression == 3: # BI_BITFIELDS compression mask = i32(read(4)), i32(read(4)), i32(read(4)) if bits == 32 and mask == (0xff0000, 0x00ff00, 0x0000ff): rawmode = "BGRX" elif bits == 16 and mask == (0x00f800, 0x0007e0, 0x00001f): rawmode = "BGR;16" elif bits == 16 and mask == (0x007c00, 0x0003e0, 0x00001f): rawmode = "BGR;15" else: # print bits, map(hex, mask) raise IOError("Unsupported BMP bitfields layout") elif compression != 0: raise IOError("Unsupported BMP compression (%d)" % compression) # LUT if self.mode == "P": palette = [] greyscale = 1 if colors == 2: indices = (0, 255) else: indices = range(colors) for i in indices: rgb = read(lutsize)[:3] if rgb != chr(i) * 3: greyscale = 0 palette.append(rgb) if greyscale: if colors == 2: self.mode = rawmode = "1" else: self.mode = rawmode = "L" else: self.mode = "P" self.palette = ImagePalette.raw("BGR", string.join(palette, "")) if not offset: offset = self.fp.tell() self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, ((self.size[0] * bits + 31) >> 3) & (~3), direction))] self.info["compression"] = compression
def chunk_gAMA(self, pos, len): # gamma setting s = ImageFile._safe_read(self.fp, len) self.im_info["gamma"] = i32(s) / 100000.0 return s
def _bitmap(self, header = 0, offset = 0): if header: self.fp.seek(header) read = self.fp.read # CORE/INFO s = read(4) s = s + ImageFile._safe_read(self.fp, i32(s)-4) if len(s) == 12: # OS/2 1.0 CORE bits = i16(s[10:]) self.size = i16(s[4:]), i16(s[6:]) compression = 0 lutsize = 3 colors = 0 direction = -1 elif len(s) in [40, 64]: # WIN 3.1 or OS/2 2.0 INFO bits = i16(s[14:]) self.size = i32(s[4:]), i32(s[8:]) compression = i32(s[16:]) lutsize = 4 colors = i32(s[32:]) direction = -1 if s[11] == b'\xff': # upside-down storage self.size = self.size[0], 2**32 - self.size[1] direction = 0 else: raise IOError("Unsupported BMP header type ({0})".format(len(s))) if not colors: colors = 1 << bits # MODE try: self.mode, rawmode = BIT2MODE[bits] except KeyError: raise IOError("Unsupported BMP pixel depth ({0})".format(bits)) if compression == 3: # BI_BITFIELDS compression mask = i32(read(4)), i32(read(4)), i32(read(4)) if bits == 32 and mask == (0xff0000, 0x00ff00, 0x0000ff): rawmode = "BGRX" elif bits == 16 and mask == (0x00f800, 0x0007e0, 0x00001f): rawmode = "BGR;16" elif bits == 16 and mask == (0x007c00, 0x0003e0, 0x00001f): rawmode = "BGR;15" else: # print(bits, map(hex, mask)) raise IOError("Unsupported BMP bitfields layout") elif compression != 0: raise IOError("Unsupported BMP compression ({0})".format(compression)) # LUT if self.mode == "P": palette = [] greyscale = 1 if colors == 2: indices = (0, 255) else: indices = range(colors) for i in indices: rgb = read(lutsize)[:3] if rgb != chr(i)*3: greyscale = 0 palette.append(rgb) if greyscale: if colors == 2: self.mode = rawmode = "1" else: self.mode = rawmode = "L" else: self.mode = "P" self.palette = ImagePalette.raw("BGR", "".join(palette)) if not offset: offset = self.fp.tell() self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, ((self.size[0]*bits+31)>>3)&(~3), direction))] self.info["compression"] = compression
def Skip(self, marker): n = i16(self.fp.read(2)) - 2 ImageFile._safe_read(self.fp, n)