Repository navigation
TIFF decode: 8-bit Palette + LZW + Predictor=2 produces near-uniform near-black pixel data #3182
Description
Activity
The real files that trigger this may contain sensitive information, so I can't post one publicly here.
Would it be possible that you send me the file via mail, so i could reproduce the issue?
Maybe it is possible to create a tiff image with similar properties with the command line tool imagemagick?
It is possible to create a tiff with the same properties like this:
magick convert img.jpg -define tiff:predictor=2 -compress lzw -colors 256 -type Palette test.tiffBut this does not seem to reproduce any issue when decoding with ImageSharp.
Thanks — your ImageMagick command was a useful clue. I was able to reduce this to a
shareable synthetic reproducer, so no private archival file is needed.Starting from a colourful JPEG, this command produces a TIFF that decodes correctly in
ImageSharp:magick convert input.jpg -define tiff:predictor=2 -compress lzw -colors 256 -type Palette normal.tiffIt has the same relevant high-level properties as the affected files: 8-bit palette
colour, LZW compression, Predictor=2, one strip, and a 256×3ColorMap. The important
difference is the range of theColorMapentries:- ImageMagick's normal output uses the TIFF-spec 16-bit range (maximum
65535) and
ImageSharp decodes it correctly. - The affected archival files use a
ColorMapwhose entries only reach255. Rewriting
only the synthetic file's 768ColorMapentries to that 0–255 range makes ImageSharp
reproduce the problem: a colourful source decodes with maximum RGB channel value1
(near-uniform black).
No image pixels, compression stream, predictor tag, dimensions, or other TIFF tags are
changed by that rewrite. Other decoders (libvips/NetVips) still show the expected colour
variation from the rewritten file.I can attach the small generated TIFF and a minimal C# test/rewrite helper if that is
useful. Does this point to the decoder treatingColorMapentries as though they were
always full-range 16-bit values, rather than scaling the observed 0–255 palette range?- ImageMagick's normal output uses the TIFF-spec 16-bit range (maximum
I can attach the small generated TIFF and a minimal C# test/rewrite helper if that is
useful.@roguestabster01 yes, that would be useful. You can drag and drop the image here in github when you start a new comment.
Thanks, those instructions were enough to reproduce this without the original image.
I've added a regression test using synthetic TIFFs that differ only in their ColorMap values. The normal 0–65535 palette passes; the 0–255 version fails.
The decoder currently treats all palette entries as full-range 16-bit values, which explains the near-black output. No additional image is needed.
Reacted by Brian Popow- linked a pull request that will close this issueFix TIFF decoding of legacy 8-bit color maps #3189
on Sep 14, 2026 Fixed via #3189
Description
Decoding a TIFF with 8-bit Palette color (
PhotometricInterpretation=3), LZW compression, and Predictor=2 (horizontal differencing) produces near-uniform, near-black pixel data across the entire image, regardless of the actual page content. The same bytes decode correctly in libvips/NetVips (NetVips.Image.NewFromFile), which I used to visually confirm the real page content and rule out a corrupt source file.Affected files in my case are real scanned document pages (2479x3504, 300dpi) from a document corpus that may contain sensitive information — 64 out of 864 sampled files, all sharing this exact tag combination, all misdecoded the same way. The other 800 files (bilevel Group4 fax-style, or 24-bit RGB LZW) decode fine.
Repro details
Tag values on the affected files (via
Image.Load+ inspecting decoded pixel data, and cross-checked with Pillow'stag_v2):PhotometricInterpretation(262) =3(Palette)BitsPerSample(258) =8Compression(259) =5(LZW)Predictor(317) =2(horizontal differencing)RowsPerStrip(278) = image height (single full-height strip, not tiled)ColorMap(320) = a 768-entry (256×3) 16-bit colormapWhat I tried
I attempted to build a minimal synthetic repro with matching tags (solid 2-color palette, and separately a richer grayscale-gradient palette image), written via Pillow with
tiffinfo={317: 2}to force the predictor tag andcompression="tiff_lzw". Both synthetic files decode correctly in ImageSharp — only the real, larger, higher-entropy archive files trigger the bug. This suggests the issue may be specific to LZW code-width transitions or something else that only manifests at realistic page size/entropy (my synthetic images were 200x200 / 400x400, far smaller and lower-entropy than the real 2479x3504 scanned pages), rather than a straightforward "predictor not applied" bug — a real minimal repro would help narrow this down but I haven't been able to construct one yet.Impact
Any blank-page / content detection, thumbnailing, or other logic built on ImageSharp's decoded pixel data for this TIFF variant will silently get garbage (near-uniform near-black) instead of the real page content — no exception is thrown, so it's a silent correctness bug rather than a crash.
Environment
Can I attach a repro file?
The real files that trigger this may contain sensitive information, so I can't post one publicly here. Happy to try harder to build a byte-exact synthetic repro, or share a sanitized/cropped file privately if that would help — let me know what would be most useful.