Repository: python-pillow/Pillow

Issue:
testsuite fails with libtiff 4.2.0
During Pillow 8.0.1 build:
```python
[   38s] =================================== FAILURES ===================================
[   38s] _____________________ TestFileLibTiff.test_custom_metadata _____________________
[   38s] 
[   38s] self = <Tests.test_file_libtiff.TestFileLibTiff object at 0x7fe05d0a2850>
[   38s] tmp_path = PosixPath('/tmp/pytest-of-abuild/pytest-2/test_custom_metadata0')
[   38s] 
[   38s]     def test_custom_metadata(self, tmp_path):
[   38s]         tc = namedtuple("test_case", "value,type,supported_by_default")
[   38s]         custom = {
[   38s]             37000 + k: v
[   38s]             for k, v in enumerate(
[   38s]                 [
[   38s]                     tc(4, TiffTags.SHORT, True),
[   38s]                     tc(123456789, TiffTags.LONG, True),
[   38s]                     tc(-4, TiffTags.SIGNED_BYTE, False),
[   38s]                     tc(-4, TiffTags.SIGNED_SHORT, False),
[   38s]                     tc(-123456789, TiffTags.SIGNED_LONG, False),
[   38s]                     tc(TiffImagePlugin.IFDRational(4, 7), TiffTags.RATIONAL, True),
[   38s]                     tc(4.25, TiffTags.FLOAT, True),
[   38s]                     tc(4.25, TiffTags.DOUBLE, True),
[   38s]                     tc("custom tag value", TiffTags.ASCII, True),
[   38s]                     tc(b"custom tag value", TiffTags.BYTE, True),
[   38s]                     tc((4, 5, 6), TiffTags.SHORT, True),
[   38s]                     tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True),
[   38s]                     tc((-4, 9, 10), TiffTags.SIGNED_BYTE, False),
[   38s]                     tc((-4, 5, 6), TiffTags.SIGNED_SHORT, False),
[   38s]                     tc(
[   38s]                         (-123456789, 9, 34, 234, 219387, -92432323),
[   38s]                         TiffTags.SIGNED_LONG,
[   38s]                         False,
[   38s]                     ),
[   38s]                     tc((4.25, 5.25), TiffTags.FLOAT, True),
[   38s]                     tc((4.25, 5.25), TiffTags.DOUBLE, True),
[   38s]                     # array of TIFF_BYTE requires bytes instead of tuple for backwards
[   38s]                     # compatibility
[   38s]                     tc(bytes([4]), TiffTags.BYTE, True),
[   38s]                     tc(bytes((4, 9, 10)), TiffTags.BYTE, True),
[   38s]                 ]
[   38s]             )
[   38s]         }
[   38s]     
[   38s]         libtiffs = [False]
[   38s]         if Image.core.libtiff_support_custom_tags:
[   38s]             libtiffs.append(True)
[   38s]     
[   38s]         for libtiff in libtiffs:
[   38s]             TiffImagePlugin.WRITE_LIBTIFF = libtiff
[   38s]     
[   38s]             def check_tags(tiffinfo):
[   38s]                 im = hopper()
[   38s]     
[   38s]                 out = str(tmp_path / "temp.tif")
[   38s]                 im.save(out, tiffinfo=tiffinfo)
[   38s]     
[   38s]                 with Image.open(out) as reloaded:
[   38s]                     for tag, value in tiffinfo.items():
[   38s]                         reloaded_value = reloaded.tag_v2[tag]
[   38s]                         if (
[   38s]                             isinstance(reloaded_value, TiffImagePlugin.IFDRational)
[   38s]                             and libtiff
[   38s]                         ):
[   38s]                             # libtiff does not support real RATIONALS
[   38s]                             assert (
[   38s]                                 round(abs(float(reloaded_value) - float(value)), 7) == 0
[   38s]                             )
[   38s]                             continue
[   38s]     
[   38s]                         assert reloaded_value == value
[   38s]     
[   38s]             # Test with types
[   38s]             ifd = TiffImagePlugin.ImageFileDirectory_v2()
[   38s]             for tag, tagdata in custom.items():
[   38s]                 ifd[tag] = tagdata.value
[   38s]                 ifd.tagtype[tag] = tagdata.type
[   38s] >           check_tags(ifd)
[   38s] 
[   38s] Tests/test_file_libtiff.py:312: 
[   38s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   38s] Tests/test_file_libtiff.py:290: in check_tags
[   38s]     im.save(out, tiffinfo=tiffinfo)
[   38s] ../../BUILDROOT/python-Pillow-8.0.1-0.x86_64/usr/lib64/python3.8/site-packages/PIL/Image.py:2151: in save
[   38s]     save_handler(self, fp, filename)
[   38s] ../../BUILDROOT/python-Pillow-8.0.1-0.x86_64/usr/lib64/python3.8/site-packages/PIL/TiffImagePlugin.py:1621: in _save
[   38s]     e = Image._getencoder(im.mode, "libtiff", a, im.encoderconfig)
[   38s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   38s] 
[   38s] mode = 'RGB', encoder_name = 'libtiff'
[   38s] args = ('RGB', 'raw', 12, '/tmp/pytest-of-abuild/pytest-2/test_custom_metadata0/temp.tif', [(256, 128), (257, 128), (258, 8), (259, 1), (262, 2), (277, 3), ...], {273: 4, 279: 4, 37000: 3, 37001: 4, ...})
[   38s] extra = ()
[   38s] 
[   38s]     def _getencoder(mode, encoder_name, args, extra=()):
[   38s]     
[   38s]         # tweak arguments
[   38s]         if args is None:
[   38s]             args = ()
[   38s]         elif not isinstance(args, tuple):
[   38s]             args = (args,)
[   38s]     
[   38s]         try:
[   38s]             encoder = ENCODERS[encoder_name]
[   38s]         except KeyError:
[   38s]             pass
[   38s]         else:
[   38s]             return encoder(mode, *args + extra)
[   38s]     
[   38s]         try:
[   38s]             # get encoder
[   38s]             encoder = getattr(core, encoder_name + "_encoder")
[   38s]         except AttributeError as e:
[   38s]             raise OSError(f"encoder {encoder_name} not available") from e
[   38s] >       return encoder(mode, *args + extra)
[   38s] E       RuntimeError: Error setting from dictionary
[   38s] 
[   38s] ../../BUILDROOT/python-Pillow-8.0.1-0.x86_64/usr/lib64/python3.8/site-packages/PIL/Image.py:462: RuntimeError
[   38s] ----------------------------- Captured stderr call -----------------------------
[   38s] _TIFFVSetField: /tmp/pytest-of-abuild/pytest-2/test_custom_metadata0/temp.tif: Bad field type 5 for "".
[   38s] =========================== short test summary info ============================
```



Discussion:

Resolving patch:
diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py
--- a/winbuild/build_prepare.py
+++ b/winbuild/build_prepare.py
@@ -141,9 +141,9 @@ def cmd_msbuild(
         "libs": [r"*.lib"],
     },
     "libtiff": {
-        "url": "https://download.osgeo.org/libtiff/tiff-4.1.0.tar.gz",
-        "filename": "tiff-4.1.0.tar.gz",
-        "dir": "tiff-4.1.0",
+        "url": "https://download.osgeo.org/libtiff/tiff-4.2.0.tar.gz",
+        "filename": "tiff-4.2.0.tar.gz",
+        "dir": "tiff-4.2.0",
         "build": [
             cmd_copy(r"{winbuild_dir}\tiff.opt", "nmake.opt"),
             cmd_nmake("makefile.vc", "clean"),


Test patch: