From 236d8e88e26523dcc99035aabdb15c766150c445 Mon Sep 17 00:00:00 2001 From: MPCoreDeveloper Date: Sat, 14 Nov 2026 23:08:22 +0100 Subject: [PATCH 1/2] Record the CCITT fixtures and what the first attempt established Two Pillow-written strips and the bitmap they must produce are committed beside the other image fixtures, with the TIFF-strip extraction method and the two facts the decoder attempt established: the raw bitmap is the complement of Pillow tobytes(), and a line may start with a zero-length white run whose transition at 0 shifts every later b1 if it is not recorded. No production code: the CCITT decoder is the next slice, and this commit makes it start from data. --- docs/adr/0005-image-filter-decoders.md | 27 ++++++++++++++++++ .../Assets/parity/images/ccitt-expected.txt | 3 ++ .../Assets/parity/images/ccitt-g3.bin | Bin 0 -> 68 bytes .../Assets/parity/images/ccitt-g4.bin | Bin 0 -> 26 bytes 4 files changed, 30 insertions(+) create mode 100644 tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt create mode 100644 tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g3.bin create mode 100644 tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g4.bin diff --git a/docs/adr/0005-image-filter-decoders.md b/docs/adr/0005-image-filter-decoders.md index 8bc7ec3..6de7a62 100644 --- a/docs/adr/0005-image-filter-decoders.md +++ b/docs/adr/0005-image-filter-decoders.md @@ -71,6 +71,33 @@ and recorded, the way this repository treats every other file. there only when the specification allows it in an object stream, which `RunLengthDecode` and the four image codecs do not. +## Fixtures for the CCITT slice (2026-11-14) + +The next slice starts from data rather than from a description. Two strips and the bitmap they must produce +are committed beside the other image fixtures: + +- `tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g4.bin` — 26 bytes, Group 4, a 16 x 16 bilevel + fixture (a diagonal and a 6 x 6 block), written by Pillow 13.0.0 through libtiff. +- `ccitt-g3.bin` — the same bitmap as Group 3 one-dimensional, 68 bytes. +- `ccitt-expected.txt` — the 16 x 16 geometry and the 32-byte bitmap Pillow decodes (`tobytes()`, 1 is + white). + +The generator is the one that produced `lzw-tiff-strip.bin`: `Image.save(format='TIFF', +compression='group4'|'group3')`, then a TIFF IFD read of `StripOffsets` (273) and `StripByteCounts` (279). + +Two facts the first attempt established, so the next one does not rediscover them: + +1. **The raw bitmap and `tobytes()` are complements.** Pillow's TIFF states a photometric that makes the + decoded samples the inverse of the mode-`1` pixels, so a decoder that fills black runs with 1 matches + `ccitt-expected.txt` only under the matching `BlackIs1` value. +2. **A line may start with a zero-length white run.** The transition at position 0 is what a line that + starts black states; a decoder that records only transitions after the first pixel shifts the parity of + every later `b1`, and the Group 4 fixture then fails on its twelfth line (a vertical mode resolves to a + position left of the current one). The fix is to record every transition, including one at 0. + +The RunLength slice is shipped; the CCITT decoder is the open work, and the Group 4 fixture now decodes its +first twelve lines correctly against this data. + ## Status of the slices | Slice | State | diff --git a/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt b/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt new file mode 100644 index 0000000..9745813 --- /dev/null +++ b/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt @@ -0,0 +1,3 @@ +width=16 +height=16 +expected=7FFFBFFFDFFFEFFFF03FF03FF03FF03FF03FF03FFFDFFFEFFFF7FFFBFFFDFFFE diff --git a/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g3.bin b/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g3.bin new file mode 100644 index 0000000000000000000000000000000000000000..46fc1e23d09fcced659136e637177ffe63993bbc GIT binary patch literal 68 zcmV-K0K5MH5yJoiYKI2^6I^gW0X2sX04A@908L*I0Ghra0X2L;0&4hx1l92X38+EL a08K)Uzy#Dd@Bo^E4}b}%IOqUPLj!=QG8Pm7 literal 0 HcmV?d00001 diff --git a/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g4.bin b/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g4.bin new file mode 100644 index 0000000000000000000000000000000000000000..0fb1978eb5106f74b1ca9d92bae0fb90fb817a62 GIT binary patch literal 26 icmY#x6Lfyl$C*;_tz!TGe@^_HtT#k+XBRLs2mk<|6$-xq literal 0 HcmV?d00001 From a368166e8e2954fffedb315ea11208311119486c Mon Sep 17 00:00:00 2001 From: MPCoreDeveloper Date: Sat, 14 Nov 2026 23:13:27 +0100 Subject: [PATCH 2/2] Keep the CCITT fixtures out of the parity corpus --- docs/adr/0005-image-filter-decoders.md | 11 +++++++---- .../Assets/ccitt/ccitt-expected.bin | 1 + .../Assets/{parity/images => ccitt}/ccitt-g3.bin | Bin .../Assets/{parity/images => ccitt}/ccitt-g4.bin | Bin .../Assets/parity/images/ccitt-expected.txt | 3 --- 5 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-expected.bin rename tests/SharpCorePDF.Tests/Assets/{parity/images => ccitt}/ccitt-g3.bin (100%) rename tests/SharpCorePDF.Tests/Assets/{parity/images => ccitt}/ccitt-g4.bin (100%) delete mode 100644 tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt diff --git a/docs/adr/0005-image-filter-decoders.md b/docs/adr/0005-image-filter-decoders.md index 6de7a62..491c27d 100644 --- a/docs/adr/0005-image-filter-decoders.md +++ b/docs/adr/0005-image-filter-decoders.md @@ -76,11 +76,14 @@ and recorded, the way this repository treats every other file. The next slice starts from data rather than from a description. Two strips and the bitmap they must produce are committed beside the other image fixtures: -- `tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g4.bin` — 26 bytes, Group 4, a 16 x 16 bilevel - fixture (a diagonal and a 6 x 6 block), written by Pillow 13.0.0 through libtiff. +- `tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-g4.bin` — 26 bytes, Group 4, a 16 x 16 bilevel fixture + (a diagonal and a 6 x 6 block), written by Pillow 13.0.0 through libtiff. - `ccitt-g3.bin` — the same bitmap as Group 3 one-dimensional, 68 bytes. -- `ccitt-expected.txt` — the 16 x 16 geometry and the 32-byte bitmap Pillow decodes (`tobytes()`, 1 is - white). +- `ccitt-expected.bin` — the 32 bytes Pillow decodes for that bitmap (`tobytes()`, 1 is white), rows padded + to a whole byte; the geometry is 16 x 16. + +They sit under `Assets/ccitt`, not `Assets/parity`, because `ParityCorpusTests` treats every file under +`Assets/parity` as a manifest entry. The generator is the one that produced `lzw-tiff-strip.bin`: `Image.save(format='TIFF', compression='group4'|'group3')`, then a TIFF IFD read of `StripOffsets` (273) and `StripByteCounts` (279). diff --git a/tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-expected.bin b/tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-expected.bin new file mode 100644 index 0000000..880b418 --- /dev/null +++ b/tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-expected.bin @@ -0,0 +1 @@ +ÿ¿ÿßÿïÿð?ð?ð?ð?ð?ð?ÿßÿïÿ÷ÿûÿýÿþ \ No newline at end of file diff --git a/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g3.bin b/tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-g3.bin similarity index 100% rename from tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g3.bin rename to tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-g3.bin diff --git a/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g4.bin b/tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-g4.bin similarity index 100% rename from tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-g4.bin rename to tests/SharpCorePDF.Tests/Assets/ccitt/ccitt-g4.bin diff --git a/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt b/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt deleted file mode 100644 index 9745813..0000000 --- a/tests/SharpCorePDF.Tests/Assets/parity/images/ccitt-expected.txt +++ /dev/null @@ -1,3 +0,0 @@ -width=16 -height=16 -expected=7FFFBFFFDFFFEFFFF03FF03FF03FF03FF03FF03FFFDFFFEFFFF7FFFBFFFDFFFE