Commit Graph
800 Commits
Author SHA1 Message Date
Lilith River 43cfc5bc3a test: self-verifying seq images with CRC32 hash in filenames
Move 74 seq-*.tiff test images to tests/images/seq/ and embed a CRC32
hash of the full decoded output (dimensions, color type, sample data)
as the last filename segment. Replace 75 individual test functions with
one generic verify_all_seq_images test that decodes each file and
validates its hash against the filename.

This catches byte-order, bit-alignment, stride, padding, and value
errors that sum-based tests would miss (e.g., swapped pixels preserve
the sum but change the hash). Adding new test images only requires
dropping a correctly-named file in seq/ — no test code changes needed.
2026-03-10 06:02:19 -06:00
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
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 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
A. Molzer cf8f96568e Expose Decoder::seek_to_directory 2026-03-04 08:59:41 +01:00
A. Molzer 4ff88e658d Rewrite Decoder::seek_to_image 2026-03-04 05:12:31 +01:00