Changed the Image getexif method to return a shared Exif instance

This commit is contained in:
Andrew Murray 2019-08-23 06:13:20 +10:00
parent 0b405c86be
commit f3ed44a566
3 changed files with 35 additions and 36 deletions

View File

@ -555,6 +555,7 @@ class Image(object):
self.category = NORMAL self.category = NORMAL
self.readonly = 0 self.readonly = 0
self.pyaccess = None self.pyaccess = None
self._exif = None
@property @property
def width(self): def width(self):
@ -1324,10 +1325,10 @@ class Image(object):
return self.im.getextrema() return self.im.getextrema()
def getexif(self): def getexif(self):
exif = Exif() if self._exif is None:
if "exif" in self.info: self._exif = Exif()
exif.load(self.info["exif"]) self._exif.load(self.info.get("exif"))
return exif return self._exif
def getim(self): def getim(self):
""" """
@ -3137,7 +3138,8 @@ class Exif(MutableMapping):
def __init__(self): def __init__(self):
self._data = {} self._data = {}
self._ifds = {} self._ifds = {}
self.info = None self._info = None
self._loaded_exif = None
def _fixup(self, value): def _fixup(self, value):
try: try:
@ -3173,15 +3175,24 @@ class Exif(MutableMapping):
# The EXIF record consists of a TIFF file embedded in a JPEG # The EXIF record consists of a TIFF file embedded in a JPEG
# application marker (!). # application marker (!).
if data == self._loaded_exif:
return
self._loaded_exif = data
self._data.clear()
self._ifds.clear()
self._info = None
if not data:
return
self.fp = io.BytesIO(data[6:]) self.fp = io.BytesIO(data[6:])
self.head = self.fp.read(8) self.head = self.fp.read(8)
# process dictionary # process dictionary
from . import TiffImagePlugin from . import TiffImagePlugin
self.info = TiffImagePlugin.ImageFileDirectory_v1(self.head) self._info = TiffImagePlugin.ImageFileDirectory_v1(self.head)
self.endian = self.info._endian self.endian = self._info._endian
self.fp.seek(self.info.next) self.fp.seek(self._info.next)
self.info.load(self.fp) self._info.load(self.fp)
# get EXIF extension # get EXIF extension
ifd = self._get_ifd_dict(0x8769) ifd = self._get_ifd_dict(0x8769)
@ -3286,29 +3297,29 @@ class Exif(MutableMapping):
return self._ifds.get(tag, {}) return self._ifds.get(tag, {})
def __str__(self): def __str__(self):
if self.info is not None: if self._info is not None:
# Load all keys into self._data # Load all keys into self._data
for tag in self.info.keys(): for tag in self._info.keys():
self[tag] self[tag]
return str(self._data) return str(self._data)
def __len__(self): def __len__(self):
keys = set(self._data) keys = set(self._data)
if self.info is not None: if self._info is not None:
keys.update(self.info) keys.update(self._info)
return len(keys) return len(keys)
def __getitem__(self, tag): def __getitem__(self, tag):
if self.info is not None and tag not in self._data and tag in self.info: if self._info is not None and tag not in self._data and tag in self._info:
self._data[tag] = self._fixup(self.info[tag]) self._data[tag] = self._fixup(self._info[tag])
if tag == 0x8825: if tag == 0x8825:
self._data[tag] = self.get_ifd(tag) self._data[tag] = self.get_ifd(tag)
del self.info[tag] del self._info[tag]
return self._data[tag] return self._data[tag]
def __contains__(self, tag): def __contains__(self, tag):
return tag in self._data or (self.info is not None and tag in self.info) return tag in self._data or (self._info is not None and tag in self._info)
if not py3: if not py3:
@ -3316,23 +3327,23 @@ class Exif(MutableMapping):
return tag in self return tag in self
def __setitem__(self, tag, value): def __setitem__(self, tag, value):
if self.info is not None: if self._info is not None:
try: try:
del self.info[tag] del self._info[tag]
except KeyError: except KeyError:
pass pass
self._data[tag] = value self._data[tag] = value
def __delitem__(self, tag): def __delitem__(self, tag):
if self.info is not None: if self._info is not None:
try: try:
del self.info[tag] del self._info[tag]
except KeyError: except KeyError:
pass pass
del self._data[tag] del self._data[tag]
def __iter__(self): def __iter__(self):
keys = set(self._data) keys = set(self._data)
if self.info is not None: if self._info is not None:
keys.update(self.info) keys.update(self._info)
return iter(keys) return iter(keys)

View File

@ -485,19 +485,9 @@ def _fixup_dict(src_dict):
def _getexif(self): def _getexif(self):
# Use the cached version if possible
try:
return self.info["parsed_exif"]
except KeyError:
pass
if "exif" not in self.info: if "exif" not in self.info:
return None return None
exif = dict(self.getexif()) return dict(self.getexif())
# Cache the result for future use
self.info["parsed_exif"] = exif
return exif
def _getmp(self): def _getmp(self):

View File

@ -86,8 +86,6 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
self.offset = self.__mpoffsets[frame] self.offset = self.__mpoffsets[frame]
self.fp.seek(self.offset + 2) # skip SOI marker self.fp.seek(self.offset + 2) # skip SOI marker
if "parsed_exif" in self.info:
del self.info["parsed_exif"]
if i16(self.fp.read(2)) == 0xFFE1: # APP1 if i16(self.fp.read(2)) == 0xFFE1: # APP1
n = i16(self.fp.read(2)) - 2 n = i16(self.fp.read(2)) - 2
self.info["exif"] = ImageFile._safe_read(self.fp, n) self.info["exif"] = ImageFile._safe_read(self.fp, n)