Skip to content

Wheel: Loading zstd-compressed TIFF fails, even with imagecodecs #9095

@sliedes

Description

@sliedes

What did you do?

I tried to load a zstd-compressed TIFF, with Pillow and imagecodecs installed:

$ uv init bug
$ cd bug
$ uv add Pillow imagecodecs
Using CPython 3.13.5
Creating virtual environment at: .venv
Resolved 4 packages in 165ms
Prepared 1 package in 4.90s
Installed 3 packages in 25ms
 + imagecodecs==2025.3.30
 + numpy==2.3.1
 + pillow==11.3.0
$ cp ~/zstd-compressed.tif test.tif
$ uv run python -c 'import numpy as np; from PIL import Image; img = Image.open("test.tif"); np.asarray(img)'
tempfile.tif: ZSTD compression support is not configured.
tempfile.tif: ZSTD compression support is not configured.
tempfile.tif: ZSTD compression support is not configured.
Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import numpy as np; from PIL import Image; img = Image.open("test.tif"); np.asarray(img)
                                                                             ~~~~~~~~~~^^^^^
  File "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/Image.py", line 735, in __array_interface__
    new["data"] = self.tobytes()
                  ~~~~~~~~~~~~^^
  File "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/Image.py", line 796, in tobytes
    self.load()
    ~~~~~~~~~^^
  File "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/TiffImagePlugin.py", line 1302, in load
    return self._load_libtiff()
           ~~~~~~~~~~~~~~~~~~^^
  File "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/TiffImagePlugin.py", line 1420, in _load_libtiff
    raise OSError(msg)
OSError: decoder error -2

What did you expect to happen?

I expected Pillow to load the zstd compressed TIFF file.

What actually happened?

See above for the backtrace.

What are your OS, Python and Pillow versions?

  • OS: NixOS
  • Python: CPython 3.13.5
  • Pillow: 11.3.0
$ uv run python3 -m PIL.report
--------------------------------------------------------------------
Pillow 11.3.0
Python 3.13.5 (main, Jun 26 2025, 21:20:04) [Clang 20.1.4 ]
--------------------------------------------------------------------
Python executable is /home/sliedes/proj/bug/bug/.venv/bin/python3
Environment Python files loaded from /home/sliedes/proj/bug/bug/.venv
System Python files loaded from /home/sliedes/.local/share/uv/python/cpython-3.13.5-linux-x86_64-gnu
--------------------------------------------------------------------
Python Pillow modules loaded from /home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL
Binary Pillow modules loaded from /home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 11.3.0
--- TKINTER support ok, loaded 8.6
--- FREETYPE2 support ok, loaded 2.13.3
--- LITTLECMS2 support ok, loaded 2.17
--- WEBP support ok, loaded 1.5.0
--- AVIF support ok, loaded 1.3.0
--- JPEG support ok, compiled for libjpeg-turbo 3.1.1
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.3
--- ZLIB (PNG/ZIP) support ok, loaded 1.3.1, compiled for zlib-ng 2.2.4
--- LIBTIFF support ok, loaded 4.7.0
*** RAQM (Bidirectional Text) support not installed
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------

Analysis

There is a libtiff.so in both Pillow and imagecodecs:

$ find -name libtiff\*
./.venv/lib/python3.13/site-packages/imagecodecs.libs/libtiff-63845e3f.so.6.1.0
./.venv/lib/python3.13/site-packages/pillow.libs/libtiff-13a02c81.so.6.1.0

I believe the imagecodecs one supports zstd compressed TIFFs, the pillow one doesn't. Now I did take a look at the _load_libtiff function, and while I don't quite understand it, maybe it does try to load the imagecodecs libtiff? But it ends up loading it from Pillow:

$ uv run strace -o t.t python -c 'import numpy as np; from PIL import Image; img = Image.open("test.tif"); np.asarray(img)'
...
$ grep 'libtiff.' t.t
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/../pillow.libs/glibc-hwcaps/x86-64-v3/libtiff-13a02c81.so.6.1.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/../pillow.libs/glibc-hwcaps/x86-64-v2/libtiff-13a02c81.so.6.1.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/../pillow.libs/libtiff-13a02c81.so.6.1.0", O_RDONLY|O_CLOEXEC) = 4

I tried importing imagecodecs._tiff before importing Pillow, but that just results in both libtiffs getting loaded and, I believe, Pillow using its own:

$ uv run strace -o t.t python -c 'import imagecodecs._tiff; import numpy as np; from PIL import Image; img = Image.open("test.tif"); np.asarray(img)'
...
$ grep 'libtiff.' t.t
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/imagecodecs/../imagecodecs.libs/glibc-hwcaps/x86-64-v3/libtiff-63845e3f.so.6.1.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/imagecodecs/../imagecodecs.libs/glibc-hwcaps/x86-64-v2/libtiff-63845e3f.so.6.1.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/imagecodecs/../imagecodecs.libs/libtiff-63845e3f.so.6.1.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/../pillow.libs/glibc-hwcaps/x86-64-v3/libtiff-13a02c81.so.6.1.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/../pillow.libs/glibc-hwcaps/x86-64-v2/libtiff-13a02c81.so.6.1.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/sliedes/proj/bug/bug/.venv/lib/python3.13/site-packages/PIL/../pillow.libs/libtiff-13a02c81.so.6.1.0", O_RDONLY|O_CLOEXEC) = 4

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions