Repository: python-pillow/Pillow

Issue:
Saving binary tiff files with `tiff_deflate` compression fails under certain conditions
### What did you do?

I have this file:

[20210415185447038_0158.zip](https://github.com/python-pillow/Pillow/files/14720473/20210415185447038_0158.zip)

(you'll have to unzip it to test, I zipped it so that I could upload it in this issue)

I'm running the following script:

```python
from PIL import Image

img = Image.open("20210415185447038_0158.tiff")
# any of these operations make the final line work
#img = img.convert("L")
#img = img.rotate(180).rotate(180)
# removing the compression argument also makes it work
img.save("test.tiff", compression="tiff_deflate")
```

### What did you expect to happen?

I expected the file to be saved

### What actually happened?

I got

```
$ python3 convert_tiff.py 
_TIFFVSetField: toto2.tiff: Ignored tag "OldSubfileType" (not supported by libtiff).
Traceback (most recent call last):
  File "/home/admin/tmp/convert_tiff.py", line 8, in <module>
    img.save("toto2.tiff", compression="tiff_deflate")
  File "/home/admin/.local/lib/python3.9/site-packages/PIL/Image.py", line 2439, in save
    save_handler(self, fp, filename)
  File "/home/admin/.local/lib/python3.9/site-packages/PIL/TiffImagePlugin.py", line 1838, in _save
    e = Image._getencoder(im.mode, "libtiff", a, encoderconfig)
  File "/home/admin/.local/lib/python3.9/site-packages/PIL/Image.py", line 420, in _getencoder
    return encoder(mode, *args + extra)
RuntimeError: Error setting from dictionary
```

### What are your OS, Python and Pillow versions?

* OS: Debian 5.10
* Python: 3.9.2
* Pillow: 10.2.0


The strange thing is that if I do anything with the image then saving works, or if I save it uncompressed it works too, it only fails when I save the untouched image.


Discussion:

Resolving patch:
diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py
--- a/src/PIL/TiffImagePlugin.py
+++ b/src/PIL/TiffImagePlugin.py
@@ -74,6 +74,7 @@
 # Read TIFF files
 
 # a few tag names, just to make the code below a bit more readable
+OSUBFILETYPE = 255
 IMAGEWIDTH = 256
 IMAGELENGTH = 257
 BITSPERSAMPLE = 258
@@ -1784,11 +1785,13 @@ def _save(im, fp, filename):
         types = {}
         # STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
         # based on the data in the strip.
+        # OSUBFILETYPE is deprecated.
         # The other tags expect arrays with a certain length (fixed or depending on
         # BITSPERSAMPLE, etc), passing arrays with a different length will result in
         # segfaults. Block these tags until we add extra validation.
         # SUBIFD may also cause a segfault.
         blocklist += [
+            OSUBFILETYPE,
             REFERENCEBLACKWHITE,
             STRIPBYTECOUNTS,
             STRIPOFFSETS,


Test patch:
diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py
--- a/Tests/test_file_libtiff.py
+++ b/Tests/test_file_libtiff.py
@@ -12,7 +12,7 @@
 import pytest
 
 from PIL import Image, ImageFilter, ImageOps, TiffImagePlugin, TiffTags, features
-from PIL.TiffImagePlugin import SAMPLEFORMAT, STRIPOFFSETS, SUBIFD
+from PIL.TiffImagePlugin import OSUBFILETYPE, SAMPLEFORMAT, STRIPOFFSETS, SUBIFD
 
 from .helper import (
     assert_image_equal,
@@ -325,6 +325,12 @@ def check_tags(
             )
         TiffImagePlugin.WRITE_LIBTIFF = False
 
+    def test_osubfiletype(self, tmp_path: Path) -> None:
+        outfile = str(tmp_path / "temp.tif")
+        with Image.open("Tests/images/g4_orientation_6.tif") as im:
+            im.tag_v2[OSUBFILETYPE] = 1
+            im.save(outfile)
+
     def test_subifd(self, tmp_path: Path) -> None:
         outfile = str(tmp_path / "temp.tif")
         with Image.open("Tests/images/g4_orientation_6.tif") as im: