Repository: python-pillow/Pillow

Issue:
TIFF EXIF data is not updated when saving image
### What did you do?
Tried to add 'Artist' and 'Copyright' exif fields to artwork.tiff
### What did you expect to happen?
Exif to be saved and viewable for artwork.tiff.
### What actually happened?
Exif data was not updated and loading the image with Pillow again also didn't show the updated data.
### What are your OS, Python and Pillow versions?

* OS: Linux
* Python: 3.10.4
* Pillow: 9.1.1

```python
img = Image.open("artwork.tiff")
exif = img.getexif()
exif[0x8298] = "test"
exif[0x013B] = "test"
img.save("artwork.tiff", exif=exif)
```

[artwork.zip](https://github.com/python-pillow/Pillow/files/8775245/artwork.zip)
The tiff in the zip above was created by converting the svg I will attach below using ImageMagick.
[artwork-00.svg](https://user-images.githubusercontent.com/8126341/170388737-9f2c3100-f3b9-4342-b483-79eee8a6f226.svg)

Pillow saved the image successfully, no failure messages were shown.


Discussion:
Hi. If you'd like an immediate workaround, adding in `img.load()` saves the data correctly.
```python
from PIL import Image
img = Image.open("artwork.tiff")
exif = img.getexif()
img.load()
exif[0x8298] = "test"
exif[0x013B] = "test"
img.save("artwork.tiff", exif=exif)
```
I've created PR #6335 to resolve this.

Resolving patch:
diff --git a/src/PIL/Image.py b/src/PIL/Image.py
--- 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 or not self._exif._loaded:
+            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
--- 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
--- 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


Test patch:
diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py
--- 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
--- 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: