TIFF parser rejects bilevel TIFFs without a BitsPerSample tag (TIFF 6.0 default is 1), e.g. 1-bit TIFFs written by Pillow
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Accessibilité débutants
- 72/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Domaine
- backend, computer-vision
Piste de recherche
Start by reading src/parsers/tiff.cpp, especially ensureParsedIfd near line 652, and compare its handling of missing BitsPerSample with the existing Grayscale_MissingSPP test and the libtiff extension’s defaulted tag read. Add parser and Python regression coverage for Pillow’s uncompressed 1-bit TIFF without that tag, alongside the explicit-tag case. Done means the missing-tag file parses and decodes to the same 5×8, single-channel, 1-bit image as the explicit-tag file; check the GPU decoder separately if available.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Version
0.10.0 (wheel nvidia-nvimgcodec-cu12==0.10.0.9; also main at 77a7d15)
Describe the bug.
A 1-bit TIFF that has no BitsPerSample tag cannot be opened:
[ERROR] [tiff_parser] Couldn't read TIFF image required fields - missing: BitsPerSample
RuntimeError: Failed to get image info
TIFF 6.0 gives BitsPerSample a default of 1 (Section 8), and it is not among the required fields for bilevel images (Section 3). Pillow writes uncompressed mode "1" images without the tag. Pillow and OpenCV read these files, and libtiff returns the default through TIFFGetFieldDefaulted.
Expected: the file decodes like the same image saved with an explicit BitsPerSample = 1, which works (5x8, 1 channel, precision 1, values 0/255).
The check is in src/parsers/tiff.cpp (ensureParsedIfd, line 652 on main). SamplesPerPixel already gets its default for grayscale files (test Grayscale_MissingSPP), and the libtiff extension reads BitsPerSample with TIFFGetFieldDefaulted.
Minimum reproducible example
cat > repro.py <<'PY'
import io
import numpy as np
from PIL import Image
from nvidia import nvimgcodec
print("nvimgcodec", nvimgcodec.__version__)
bits = np.arange(40).reshape(5, 8) % 3 == 0
pil_image = Image.fromarray(bits) # mode "1"
decoder = nvimgcodec.Decoder(
device_id=nvimgcodec.NVIMGCODEC_DEVICE_CPU_ONLY,
backends=[nvimgcodec.Backend(nvimgcodec.BackendKind.CPU_ONLY)],
)
params = nvimgcodec.DecodeParams(color_spec=nvimgcodec.ColorSpec.UNCHANGED)
# "raw" is Pillow's own writer (no BitsPerSample tag); "tiff_lzw" goes through libtiff (tag present).
for compression in ("tiff_lzw", "raw"):
buf = io.BytesIO()
pil_image.save(buf, "TIFF", compression=compression)
data = buf.getvalue()
has_tag = 258 in Image.open(io.BytesIO(data)).tag_v2
print(f"--- compression={compression}, BitsPerSample tag present: {has_tag}")
try:
code_stream = nvimgcodec.CodeStream(data)
print("parsed:", code_stream.height, code_stream.width, code_stream.num_channels,
code_stream.dtype, "precision", code_stream.precision)
image = decoder.decode(code_stream, params=params)
decoded = None if image is None else np.asarray(image.cpu())[:, :, 0]
print("decoded matches Pillow:",
decoded is not None and np.array_equal(decoded, bits.astype(np.uint8) * 255))
except Exception as e:
print("ERROR:", type(e).__name__, e)
PY
python repro.py
Environment details
tools/print_env.sh was not run. Environment used for the repro:
x86_64 Linux, Ubuntu 24.04, Python 3.12
nvidia-nvimgcodec-cu12 0.10.0.9, Pillow 13.0.0, numpy 2.5.4
CPU-only backend, no GPU visible (CUDA_VISIBLE_DEVICES empty)
Also reproduced with a from-source build of main 77a7d15 (CUDA toolkit 12.9, GCC 14.4, libtiff 4.7.2)
Relevant log output
[ERROR] [tiff_parser] Couldn't read TIFF image required fields - missing: BitsPerSample (IFD at offset 8, entry_count=8)
nvimgcodec 0.10.0
--- compression=tiff_lzw, BitsPerSample tag present: True
parsed: 5 8 1 uint8 precision 1
decoded matches Pillow: True
--- compression=raw, BitsPerSample tag present: False
ERROR: RuntimeError Failed to get image info
Other/Misc.
The error message calls BitsPerSample a required field, so this check may be deliberate. If it is not, a small local parser change is available: use 1 when the tag is absent, as libtiff does. It comes with a parser test and a Python test. Two questions for you:
- Should the default apply to every photometric type, as in libtiff, or only to single-channel images?
- The change was not tested with the nvTIFF GPU decoder, because that extension was not in the local build. The CPU path (libtiff extension) decodes the file correctly.
Check for duplicates
- I have searched the open bugs/issues and have found no duplicates for this bug report
This was found with an AI coding assistant (Claude Code, claude-fable-5-2), which also wrote and ran the repro above and drafted this report.
- Langage dominant
- Jupyter Notebook
- Étoiles
- 164
- Forks
- 26
- Merge moyen
- 27 min
- PR mergées (30 j)
- 1
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Aucun modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de NVIDIA/nvImageCodec
-
Difficulté 2/5 1-3 heures Accessibilité débutants 79/100
NVIDIA/nvImageCodec#65 · 1 commentaire ·
-
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 38/100
NVIDIA/nvImageCodec#64 ·
-
nvjpeg2k error 3 (Bad jpeg) on valid JPEG 2000 aerial photos that OpenJPEG and ffmpeg decode identicallyPeut-être pris @mkepa-nv l’a pris il y a 6 jours. Ouvertebug
NVIDIA/nvImageCodec#63 · 2 commentaires · 1 personne assignée ·
-
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 8/100
NVIDIA/nvImageCodec#60 ·
-
enhancement
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 35/100
NVIDIA/nvImageCodec#59 ·
Toutes les issues de NVIDIA/nvImageCodec
Issues similaires
-
bug
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
jupyterlite/jupyterlite#2111 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
databricks/databricks-sql-python#1034 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
Les mainteneurs répondent en général sous 3 jours
-
Markdown and Astro language servers do not start when the project path contains a non-ASCII character or a spacePeut-être pris @RoiSoleil l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
eclipse-wildwebdeveloper/wildwebdeveloper#2277 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 77/100
tauri-apps/plugins-workspace#3780 ·
Les mainteneurs répondent en général sous 3 jours