Lilith River
c3977c4513
test: expand test suite to 74 images with libtiff reference decoder
...
Add 19 new libtiff-generated test images and a reference decoder
(verify_seq_tiff.c) that independently verifies all checksums using
libtiff's own read path, giving three-way agreement:
libtiff writer → libtiff reader → image-tiff reader
New coverage:
- Standard sub-byte: 1-bit, 2-bit, 4-bit grayscale (BIZ + WIZ)
- Multi-strip: RowsPerStrip=4 (gray 8/16, RGB 8)
- Tiled + compressed: LZW and Deflate tiles
- Float predictor: f32/f64 + Deflate + predictor=3
- Unassociated alpha: RGBA 8-bit with EXTRASAMPLE_UNASSALPHA
- Sub-byte RGB: 5-bit and 7-bit contiguous
- Signed RGB: i8 and i16 (3-channel, decoded as Multiband)
- Float f64 RGB
- Tiled BigTIFF
verify_seq_tiff.c: reads each TIFF with libtiff, computes matching
checksums (handling packed sub-byte, unpacked extended, float, signed),
and verifies 68/68 cases pass.
Total: 74 test images (66.8 KB), 317 tests all passing.
2026-03-10 06:02:19 -06:00
Lilith River
a4cbf7bbaf
test: add 28 format-variant test images covering compression, tiled, BigTIFF, float, signed, CMYK, palette, RGBA, multi-page, and big-endian
...
Expand gen_seq_tiff.c with writers for standard-depth formats that exercise
different decoder code paths. All 55 seq-* images are 16x16, libtiff-generated,
and cross-validated against tifffile.
New coverage:
- Compression: LZW, Deflate, PackBits (gray 8/16-bit, RGB 8-bit)
- LZW + horizontal predictor (8-bit gray)
- Tiled layout: gray 8/16-bit, RGB 8-bit (16x16 tiles)
- BigTIFF: gray 8-bit, RGB 16-bit
- Float: gray f32/f64, RGB f32
- Signed integer: i8, i16, i32
- CMYK: 8-bit, 16-bit
- Palette/indexed: 4-bit, 8-bit (with known colormap)
- RGBA with associated alpha: 8-bit, 16-bit
- Multi-page: 3-page gray 8-bit (all pages verified)
- Big-endian byte order: gray 8/16-bit, RGB 8-bit
Total: 298 tests, all passing.
2026-03-10 06:02:19 -06:00
Lilith River
26c32431fa
test: regenerate seq-* test images using libtiff C API
...
Replace Python-generated test TIFFs with libtiff-generated ones to
eliminate circular validation. The C program (gen_seq_tiff.c) uses
libtiff's TIFFWriteScanline with MSB-first packed bit streams.
Cross-validated: tifffile independently confirms all 27 images match
the original Python-generated versions byte-for-byte. tiffinfo validates
all IFD structures. All 27 image-tiff decode tests pass unchanged.
2026-03-10 06:02:19 -06:00
Lilith River
5090003bda
test: add 27 sequential-value test images for bit-error detection
...
Generated by gen_seq_images.py using manual TIFF writer with packed
bit streams matching TIFF spec. Each 16x16 image has cycling 0..max
values so any bit-level decode error changes the checksum.
Test matrix:
- Sub-byte BlackIsZero: 3/5/7-bit
- Sub-byte WhiteIsZero: 3/5/6/7-bit
- Extended BlackIsZero: 10/12/14/24-bit
- Extended WhiteIsZero: 10/12/14/24-bit
- Extended HPredict: 10/12/14/24-bit
- RGB contiguous: 10/12/14/24-bit
- RGB planar: 10/12/14/24-bit (first plane only via read_image)
2026-03-10 06:02:19 -06:00
Lilith River
fb1afc81e9
fix: handle WhiteIsZero for non-standard sub-byte depths (3/5/6/7-bit)
...
For sub-byte depths where samples cross byte boundaries (3, 5, 6, 7-bit),
byte-wise NOT corrupts samples. Added per-sample inversion that extracts
each N-bit sample from the packed stream, computes (max - value), and
writes it back.
Tests cover:
- 3/5/7-bit BlackIsZero (verify basic decoding)
- 3-bit and 6-bit WhiteIsZero (verify per-sample inversion)
2026-03-10 06:02:19 -06:00
Lilith River
29e43d2314
fix: handle WhiteIsZero for extended bit depths, add comprehensive tests
...
Fix invert_colors to support extended bit depths (9-15 promoted to u16,
17-31 promoted to u32). Byte-wise NOT doesn't work for promoted samples
because it flips unused upper bits; use (max - value) instead.
Add regression tests covering the extended depth matrix:
- Gray 10/14/24-bit (contiguous, BlackIsZero)
- RGB 10/14/24-bit (contiguous)
- RGB 10/12/14/24-bit (planar)
- Gray 12-bit with WhiteIsZero (synthetic 4x2 image)
- Gray 12-bit with horizontal predictor (synthetic 4x2 image)
2026-03-10 06:02:19 -06:00
Lilith River
4ff374990e
feat: accept sub-byte bit depths for all color types
...
Previously, sub-byte bit depths (1-7 bits per sample) were only
accepted for Gray and Multiband color types. This extends the
validation to accept all color types (RGB, RGBA, CMYK, CMYKA, YCbCr)
at sub-byte depths.
The data format is unchanged: sub-byte samples remain packed MSB-first
in the output buffer, exactly as for grayscale. Predictors are still
rejected for sub-byte data.
Tested via libtiffpic flower-rgb-contig-02/04 and flower-rgb-planar-02/04.
2026-03-10 06:02:19 -06:00
Lilith River
3d3c16e26f
feat: support packed extended bit depths (9-15, 17-31 bits per sample)
...
TIFF files can store samples at non-standard bit depths (e.g. 10, 12,
14, 24 bits) packed tightly in a continuous bit stream. Previously
these were rejected as unsupported color types.
This adds:
- MSB-first bit extraction from packed byte streams (unpack_bits,
extract_bits_msb) to expand N-bit samples to standard-width output
(9-16 bit → u16, 17-32 bit → u32)
- Output buffer sizing using the promoted sample width instead of the
packed bit depth (output_bits_per_sample field in ReadoutLayout)
- A new code path in expand_chunk that reads packed rows, unpacks to
standard-width samples, then applies predictor and color inversion
- Horizontal predictor support for extended depths
Tested with 12-bit grayscale and RGB images (existing test suite),
plus all libtiffpic depth test images (10/12/14/24-bit in gray, RGB
contig, and RGB planar configurations).
2026-03-10 06:01:48 -06:00
Aurelia Molzer
8a5c2da511
Merge pull request #361 from lilith/feat/palette-support
...
Support palette (ColorMap) image decoding
2026-03-10 04:15:52 +00:00
Lilith River
3b11e2f577
feat: support palette (ColorMap) image decoding
...
Read the ColorMap tag (320) for RGBPalette images and return raw
palette indices as the decoded data with ColorType::Palette(n).
Changes:
- Read and validate ColorMap tag during IFD parsing (3 * 2^bps entries)
- Return ColorType::Palette from colortype() for RGBPalette images
- Accept Palette in expand_chunk validation (standard + sub-byte depths)
- Expose color_map() method on Decoder for palette lookup
- Add tests for 1-bit, 4-bit, 8-bit palette images with checksums
- Add test verifying ColorMap accessibility and structure
The decoder returns raw palette indices; consumers apply the lookup
using the color map returned by Decoder::color_map().
2026-03-09 21:03:30 -06:00
Aurelia Molzer
c6f6ff4c95
Merge pull request #359 from image-rs/tile-offset-compatibility
...
Tile offset compatibility
2026-03-08 02:29:15 +00:00
A. Molzer
d7d24d0f7c
Changelog entry for tile treatment
2026-03-08 03:00:15 +01:00
A. Molzer
58e93fb8a3
Align tile detection to libtiff
2026-03-08 03:00:15 +01:00
Aurelia Molzer
595e67e5fb
Merge pull request #358 from image-rs/open-behavior-documentation
...
Document `Decoder::open` behavior
2026-03-06 20:15:29 +00:00
A. Molzer
812bc970ba
Document Decoder::open behavior
2026-03-06 21:09:32 +01:00
Aurelia Molzer
82b646298d
Merge pull request #356 from Shnatsel/better-docs
...
Improve documentation on compression and predictor
2026-03-06 19:12:56 +00:00
Sergey "Shnatsel" Davidoff
22ff2b5c50
Merge pull request #355 from Shnatsel/drop-exact-level
...
Drop obsolete Deflate::exact_level()
2026-03-06 18:49:06 +00:00
Sergey "Shnatsel" Davidoff
3a6492f251
More docs on the predictor
2026-03-06 15:46:37 +00:00
Sergey "Shnatsel" Davidoff
a03eeccfe5
Document Compression enum variants
2026-03-06 14:47:44 +00:00
Sergey "Shnatsel" Davidoff
287fcb9309
Drop obsolete Deflate::exact_level()
2026-03-06 14:40:37 +00:00
Sergey "Shnatsel" Davidoff
ba97bad411
Merge branch 'main' into better-docs
2026-03-06 14:39:37 +00:00
Aurelia Molzer
c4ab46ad2c
Merge pull request #354 from Shnatsel/derive-debug
...
Derive useful traits on public types
2026-03-06 11:45:45 +00:00
Sergey "Shnatsel" Davidoff
eaf9cc1d6c
Merge branch 'main' into better-docs
2026-03-06 11:02:09 +00:00
Sergey "Shnatsel" Davidoff
34191fa9ca
Merge branch 'main' into derive-debug
2026-03-06 10:55:44 +00:00
Sergey "Shnatsel" Davidoff
b0bd33dbe4
Remove equality from rational types; can be implemented later via cross-multiplication
2026-03-06 10:54:37 +00:00
Sergey "Shnatsel" Davidoff
2ca2427c75
cargo fmt
2026-03-06 10:51:23 +00:00
Aurelia Molzer
e8be8656f2
Merge pull request #353 from Shnatsel/non-exhaustive-compression
...
Make Compression enum non-exhaustive
2026-03-06 10:45:28 +00:00
Sergey "Shnatsel" Davidoff
ea949032a2
cargo clippy --fix
2026-03-06 10:43:54 +00:00
Sergey "Shnatsel" Davidoff
87007d85a0
Derive Debug on Compression enum
2026-03-06 10:41:20 +00:00
Sergey "Shnatsel" Davidoff
2119bff354
More derives on TIFF value structs
2026-03-06 10:36:12 +00:00
Sergey "Shnatsel" Davidoff
c62a69ec9d
Expand predictor docs
2026-03-06 10:07:06 +00:00
Sergey "Shnatsel" Davidoff
79a791b49a
Clarify predictor docs
2026-03-06 10:02:24 +00:00
Sergey "Shnatsel" Davidoff
e1e9f36c5a
Make Compression enum non-exhaustive
2026-03-06 09:49:10 +00:00
Sergey "Shnatsel" Davidoff
19caae4f53
Rename safe-rust-zstd to zstd-safe-rust
2026-03-06 09:36:09 +00:00
Aurelia Molzer
0ad653433a
Merge pull request #352 from image-rs/iterate-over-raw-tiff-or-exif
...
Open a Tiff without interpreting the first directory
2026-03-06 08:34:19 +00:00
A. Molzer
bf79af8de4
Add Decoder::open, deprecate new
2026-03-06 09:31:23 +01:00
Aurelia Molzer
54dddc4943
Merge pull request #347 from image-rs/iterate-over-raw-tiff-or-exif
...
Enable iteration over raw, malformed tiff or exif
2026-03-06 07:31:13 +00:00
A. Molzer
be9b3a04b9
Expand documentation with TiffHeader
2026-03-06 06:05:32 +01:00
A. Molzer
08f1b25fac
Drafting release notes
2026-03-06 05:35:45 +01:00
A. Molzer
c7b97519a0
Error guarantee on decoder IFD iteration
2026-03-06 04:42:02 +01:00
A. Molzer
e093e15bbe
Remove redundant next_ifd attribute
2026-03-06 03:44:08 +01:00
A. Molzer
647e9b4a81
Add TiffHeader to open a file without seeking
2026-03-06 02:59:45 +01:00
Aurelia Molzer
31c49ea6ef
Merge pull request #351 from Shnatsel/semver-breaking-deflate-level
...
Implement DEFLATE compression level control properly, with a semver break
2026-03-05 20:12:27 +00:00
Sergey "Shnatsel" Davidoff
0362e6e31d
Implement DEFLATE compression level control properly, with a semver break
2026-03-05 17:59:18 +00:00
Sergey "Shnatsel" Davidoff
0fe5b2804e
Merge pull request #348 from Shnatsel/deflate-level
...
Expose precise DEFLATE level controls
2026-03-05 17:23:59 +00:00
Sergey "Shnatsel" Davidoff
61dbcc1392
Add error handling
2026-03-05 13:15:33 +00:00
Sergey "Shnatsel" Davidoff
d9d4f0a905
Add safe Rust Zstd decoding option
2026-03-05 13:10:07 +00:00
Sergey "Shnatsel" Davidoff
a589010099
Fix typo
2026-03-05 12:22:37 +00:00
Sergey "Shnatsel" Davidoff
53498074a4
Merge impl blocks
2026-03-05 12:22:25 +00:00
Sergey "Shnatsel" Davidoff
cb543cded7
Expose precise DEFLATE level controls
2026-03-05 11:58:18 +00:00