From 0aad5603f45267eb0120f71afda9d75584a3eb0f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 26 May 2022 22:49:34 +1000 Subject: [PATCH] Once Exif data is parsed, do not reload unless it changes --- Tests/test_file_mpo.py | 9 +++++++++ Tests/test_file_tiff.py | 20 ++++++++++++++++++++ src/PIL/Image.py | 10 ++++++++++ src/PIL/MpoImagePlugin.py | 2 ++ src/PIL/TiffImagePlugin.py | 1 + 5 files changed, 42 insertions(+) diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index d9b59321be4..d093f26ccd8 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -124,6 +124,15 @@ def test_parallax(): assert exif.get_ifd(0x927C)[0xB211] == -3.125 +def test_reload_exif_after_seek(): + with Image.open("Tests/images/sugarshack.mpo") as im: + exif = im.getexif() + del exif[296] + + im.seek(1) + assert 296 in exif + + def test_mp(): for test_file in test_files: with Image.open(test_file) as im: diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index d03f7c736de..8706cb950dd 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -497,6 +497,26 @@ def check_exif(exif): exif = im.getexif() check_exif(exif) + def test_modify_exif(self, tmp_path): + outfile = str(tmp_path / "temp.tif") + with Image.open("Tests/images/ifd_tag_type.tiff") as im: + exif = im.getexif() + exif[256] = 100 + + im.save(outfile, exif=exif) + + with Image.open(outfile) as im: + exif = im.getexif() + assert exif[256] == 100 + + def test_reload_exif_after_seek(self): + with Image.open("Tests/images/multipage.tiff") as im: + exif = im.getexif() + del exif[256] + im.seek(1) + + assert 256 in exif + def test_exif_frames(self): # Test that EXIF data can change across frames with Image.open("Tests/images/g4-multi.tiff") as im: diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 5b7a50e1806..a9c7e4b6bb2 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1383,6 +1383,10 @@ def get_value(element): def getexif(self): if self._exif is None: self._exif = Exif() + self._exif._loaded = False + elif self._exif._loaded: + return self._exif + self._exif._loaded = True exif_info = self.info.get("exif") if exif_info is None: @@ -1407,6 +1411,12 @@ def getexif(self): return self._exif + def _reload_exif(self): + if self._exif is None: + return + self._exif._loaded = False + self.getexif() + def getim(self): """ Returns a capsule that points to the internal image memory. diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py index fc3f8556ff7..27c30958c9c 100644 --- a/src/PIL/MpoImagePlugin.py +++ b/src/PIL/MpoImagePlugin.py @@ -82,6 +82,7 @@ def seek(self, frame): if i16(segment) == 0xFFE1: # APP1 n = i16(self.fp.read(2)) - 2 self.info["exif"] = ImageFile._safe_read(self.fp, n) + self._reload_exif() mptype = self.mpinfo[0xB002][frame]["Attribute"]["MPType"] if mptype.startswith("Large Thumbnail"): @@ -90,6 +91,7 @@ def seek(self, frame): self._size = (exif[40962], exif[40963]) elif "exif" in self.info: del self.info["exif"] + self._reload_exif() self.tile = [("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))] self.__frame = frame diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 7cfd76af0db..78a7fd14d71 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1136,6 +1136,7 @@ def _seek(self, frame): self.__frame += 1 self.fp.seek(self._frame_pos[frame]) self.tag_v2.load(self.fp) + self._reload_exif() # fill the legacy tag/ifd entries self.tag = self.ifd = ImageFileDirectory_v1.from_v2(self.tag_v2) self.__frame = frame