def load(self, fp): self.reset() self._offset = fp.tell() try: for i in range(self._unpack("H", self._ensure_read(fp, 2))[0]): tag, typ, count, data = self._unpack("HHL4s", self._ensure_read(fp, 12)) if DEBUG: tagname = TAGS_V2.get(tag, TagInfo()).name typname = TYPES.get(typ, "unknown") print( "tag: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ), end=" ") try: unit_size, handler = self._load_dispatch[typ] except KeyError: if DEBUG: print("- unsupported type", typ) continue # ignore unsupported type size = count * unit_size if size > 4: here = fp.tell() offset, = self._unpack("L", data) if DEBUG: print( "Tag Location: %s - Data Location: %s" % (here, offset), end=" ") fp.seek(offset) data = ImageFile._safe_read(fp, size) fp.seek(here) else: data = data[:size] if len(data) != size: warnings.warn( "Possibly corrupt EXIF data. " "Expecting to read %d bytes but only got %d. " "Skipping tag %s" % (size, len(data), tag)) continue self._tagdata[tag] = data self.tagtype[tag] = typ if DEBUG: if size > 32: print("- value: <table: %d bytes>" % size) else: print("- value:", self[tag]) self.next, = self._unpack("L", self._ensure_read(fp, 4)) except IOError as msg: warnings.warn(str(msg)) return
def load(self, fp): self.reset() self._offset = fp.tell() try: for i in range(self._unpack("H", self._ensure_read(fp, 2))[0]): tag, typ, count, data = self._unpack("HHL4s", self._ensure_read(fp, 12)) if DEBUG: tagname = TAGS_V2.get(tag, TagInfo()).name typname = TYPES.get(typ, "unknown") print("tag: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ), end=" ") try: unit_size, handler = self._load_dispatch[typ] except KeyError: if DEBUG: print("- unsupported type", typ) continue # ignore unsupported type size = count * unit_size if size > 4: here = fp.tell() offset, = self._unpack("L", data) if DEBUG: print("Tag Location: %s - Data Location: %s" % (here, offset), end=" ") fp.seek(offset) data = ImageFile._safe_read(fp, size) fp.seek(here) else: data = data[:size] if len(data) != size: warnings.warn( "Possibly corrupt EXIF data. " "Expecting to read %d bytes but only got %d. " "Skipping tag %s" % (size, len(data), tag)) continue self._tagdata[tag] = data self.tagtype[tag] = typ if DEBUG: if size > 32: print("- value: <table: %d bytes>" % size) else: print("- value:", self[tag]) self.next, = self._unpack("L", self._ensure_read(fp, 4)) except IOError as msg: warnings.warn(str(msg)) return
def save(self, fp): if fp.tell() == 0: # skip TIFF header on subsequent pages # tiff header -- PIL always starts the first IFD at offset 8 fp.write(self._prefix + self._pack("HL", 42, 8)) # FIXME What about tagdata? fp.write(self._pack("H", len(self._tags_v2))) entries = [] offset = fp.tell() + len(self._tags_v2) * 12 + 4 stripoffsets = None # pass 1: convert tags to binary format # always write tags in ascending order for tag, value in sorted(self._tags_v2.items()): if tag == STRIPOFFSETS: stripoffsets = len(entries) typ = self.tagtype.get(tag) if DEBUG: print("Tag %s, Type: %s, Value: %s" % (tag, typ, value)) values = value if isinstance(value, tuple) else (value,) data = self._write_dispatch[typ](self, *values) if DEBUG: tagname = TAGS_V2.get(tag, TagInfo()).name typname = TYPES.get(typ, "unknown") print("save: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ), end=" ") if len(data) >= 16: print("- value: <table: %d bytes>" % len(data)) else: print("- value:", values) # count is sum of lengths for string and arbitrary data count = len(data) if typ in [2, 7] else len(values) # figure out if data fits into the entry if len(data) <= 4: entries.append((tag, typ, count, data.ljust(4, b"\0"), b"")) else: entries.append((tag, typ, count, self._pack("L", offset), data)) offset += (len(data) + 1) // 2 * 2 # pad to word # update strip offset data to point beyond auxiliary data if stripoffsets is not None: tag, typ, count, value, data = entries[stripoffsets] if data: raise NotImplementedError( "multistrip support not yet implemented") value = self._pack("L", self._unpack("L", value)[0] + offset) entries[stripoffsets] = tag, typ, count, value, data # pass 2: write entries to file for tag, typ, count, value, data in entries: if DEBUG > 1: print(tag, typ, count, repr(value), repr(data)) fp.write(self._pack("HHL4s", tag, typ, count, value)) # -- overwrite here for multi-page -- fp.write(b"\0\0\0\0") # end of entries # pass 3: write auxiliary data to file for tag, typ, count, value, data in entries: fp.write(data) if len(data) & 1: fp.write(b"\0") return offset
fp.write(self._pack("HHL4s", tag, typ, count, value)) # -- overwrite here for multi-page -- fp.write(b"\0\0\0\0") # end of entries # pass 3: write auxiliary data to file for tag, typ, count, value, data in entries: fp.write(data) if len(data) & 1: fp.write(b"\0") return offset ImageFileDirectory_v2._load_dispatch = _load_dispatch ImageFileDirectory_v2._write_dispatch = _write_dispatch for idx, name in TYPES.items(): name = name.replace(" ", "_") setattr(ImageFileDirectory_v2, "load_" + name, _load_dispatch[idx][1]) setattr(ImageFileDirectory_v2, "write_" + name, _write_dispatch[idx]) del _load_dispatch, _write_dispatch, idx, name # Legacy ImageFileDirectory support. class ImageFileDirectory_v1(ImageFileDirectory_v2): """This class represents the **legacy** interface to a TIFF tag directory. Exposes a dictionary interface of the tags in the directory:: ifd = ImageFileDirectory_v1() ifd[key] = 'Some Data' ifd.tagtype[key] = 2
def save(self, fp): if fp.tell() == 0: # skip TIFF header on subsequent pages # tiff header -- PIL always starts the first IFD at offset 8 fp.write(self._prefix + self._pack("HL", 42, 8)) # FIXME What about tagdata? fp.write(self._pack("H", len(self._tags_v2))) entries = [] offset = fp.tell() + len(self._tags_v2) * 12 + 4 stripoffsets = None # pass 1: convert tags to binary format # always write tags in ascending order for tag, value in sorted(self._tags_v2.items()): if tag == STRIPOFFSETS: stripoffsets = len(entries) typ = self.tagtype.get(tag) if DEBUG: print("Tag %s, Type: %s, Value: %s" % (tag, typ, value)) values = value if isinstance(value, tuple) else (value, ) data = self._write_dispatch[typ](self, *values) if DEBUG: tagname = TAGS_V2.get(tag, TagInfo()).name typname = TYPES.get(typ, "unknown") print("save: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ), end=" ") if len(data) >= 16: print("- value: <table: %d bytes>" % len(data)) else: print("- value:", values) # count is sum of lengths for string and arbitrary data count = len(data) if typ in [2, 7] else len(values) # figure out if data fits into the entry if len(data) <= 4: entries.append((tag, typ, count, data.ljust(4, b"\0"), b"")) else: entries.append((tag, typ, count, self._pack("L", offset), data)) offset += (len(data) + 1) // 2 * 2 # pad to word # update strip offset data to point beyond auxiliary data if stripoffsets is not None: tag, typ, count, value, data = entries[stripoffsets] if data: raise NotImplementedError( "multistrip support not yet implemented") value = self._pack("L", self._unpack("L", value)[0] + offset) entries[stripoffsets] = tag, typ, count, value, data # pass 2: write entries to file for tag, typ, count, value, data in entries: if DEBUG > 1: print(tag, typ, count, repr(value), repr(data)) fp.write(self._pack("HHL4s", tag, typ, count, value)) # -- overwrite here for multi-page -- fp.write(b"\0\0\0\0") # end of entries # pass 3: write auxiliary data to file for tag, typ, count, value, data in entries: fp.write(data) if len(data) & 1: fp.write(b"\0") return offset
# -- overwrite here for multi-page -- fp.write(b"\0\0\0\0") # end of entries # pass 3: write auxiliary data to file for tag, typ, count, value, data in entries: fp.write(data) if len(data) & 1: fp.write(b"\0") return offset ImageFileDirectory_v2._load_dispatch = _load_dispatch ImageFileDirectory_v2._write_dispatch = _write_dispatch for idx, name in TYPES.items(): name = name.replace(" ", "_") setattr(ImageFileDirectory_v2, "load_" + name, _load_dispatch[idx][1]) setattr(ImageFileDirectory_v2, "write_" + name, _write_dispatch[idx]) del _load_dispatch, _write_dispatch, idx, name # Legacy ImageFileDirectory support. class ImageFileDirectory_v1(ImageFileDirectory_v2): """This class represents the **legacy** interface to a TIFF tag directory. Exposes a dictionary interface of the tags in the directory:: ifd = ImageFileDirectory_v1() ifd[key] = 'Some Data' ifd.tagtype[key] = 2