-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Open
Labels
Description
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