You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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's tag_v2):
PhotometricInterpretation (262) = 3 (Palette)
BitsPerSample (258) = 8
Compression (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 colormap
Typical size: 2479×3504
What 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 and compression="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
SixLabors.ImageSharp 4.1.0
.NET 10.0, Windows
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.
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:
It has the same relevant high-level properties as the affected files: 8-bit palette
colour, LZW compression, Predictor=2, one strip, and a 256×3 ColorMap. The important
difference is the range of the ColorMap entries:
ImageMagick's normal output uses the TIFF-spec 16-bit range (maximum 65535) and
ImageSharp decodes it correctly.
The affected archival files use a ColorMap whose entries only reach 255. Rewriting
only the synthetic file's 768 ColorMap entries to that 0–255 range makes ImageSharp
reproduce the problem: a colourful source decodes with maximum RGB channel value 1
(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 treating ColorMap entries as though they were
always full-range 16-bit values, rather than scaling the observed 0–255 palette range?
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.
Activity
brianpopow commentedon Aug 26, 2026
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?
brianpopow commentedon Aug 27, 2026
It is possible to create a tiff with the same properties like this:
But this does not seem to reproduce any issue when decoding with ImageSharp.
roguestabster01 commentedon Aug 29, 2026
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:
It has the same relevant high-level properties as the affected files: 8-bit palette
colour, LZW compression, Predictor=2, one strip, and a 256×3
ColorMap. The importantdifference is the range of the
ColorMapentries:65535) andImageSharp decodes it correctly.
ColorMapwhose entries only reach255. Rewritingonly the synthetic file's 768
ColorMapentries to that 0–255 range makes ImageSharpreproduce the problem: a colourful source decodes with maximum RGB channel value
1(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 treating
ColorMapentries as though they werealways full-range 16-bit values, rather than scaling the observed 0–255 palette range?
brianpopow commentedon Aug 31, 2026
@roguestabster01 yes, that would be useful. You can drag and drop the image here in github when you start a new comment.
JimBobSquarePants commentedon Sep 14, 2026
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.
JimBobSquarePants commentedon Sep 14, 2026
Fixed via #3189