Skip to content

A stencil needs decoded bytes, not compressed ones - #20

Merged
tannevaled merged 1 commit into
mainfrom
fix/stencil-needs-decoded-bytes
Aug 27, 2026
Merged

A stencil needs decoded bytes, not compressed ones#20
tannevaled merged 1 commit into
mainfrom
fix/stencil-needs-decoded-bytes

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

decodeImage asks whether an image is a mask before it asks whether the filter
chain finished, so a mask whose filter stopped at an image format nothing here
decodes was handed to the stencil path still compressed — and drawn. A stencil
is one bit a pixel; compressed bytes painted through it are noise in the shape
of nothing at all.

This is not a rare shape. 273 of the image masks in the 1 633 real forms carry
an encoded filter: 236 CCITT and 9 JBIG2. Fifty-one first pages of real forms
were showing that noise, and it took decoding faxes in the reader
(go-pdfkit/reader#15) to make it visible: those pages came out with less ink
afterwards, because most of a form is white and the noise was not.

The remaining nine are JBIG2, which nothing here decodes. Until something does,
the honest answer is the one the rest of decodeImage already gives: "the image
is not drawn rather than drawn wrong."

The test draws a mask of eight zero bytes — as samples, a solid black stencil,
so anything drawn at all is visible — once with /Filter /JBIG2Decode and once
with no filter, and requires the first to draw nothing and the second to draw.
Against the parent commit the first fails with "drawn = true, want false".

100% statement coverage, go vet clean, nine cross-compile targets.

decodeImage asks whether an image is a mask before it asks whether the filter
chain finished, so a mask whose filter stopped at an image format nothing here
decodes was handed to the stencil path still compressed — and drawn. A stencil
is one bit a pixel; compressed bytes painted through it are noise in the shape
of nothing at all.

This is not a rare shape. 273 of the image masks in the 1 633 real forms carry
an encoded filter: 236 CCITT and 9 JBIG2. Fifty-one first pages of real forms
were showing that noise, and it took decoding faxes in the reader
(go-pdfkit/reader#15) to make it visible: those pages came out with *less* ink
afterwards, because most of a form is white and the noise was not.

The remaining nine are JBIG2, which nothing here decodes. Until something does,
the honest answer is the one the rest of decodeImage already gives: "the image
is not drawn rather than drawn wrong."

The test draws a mask of eight zero bytes — as samples, a solid black stencil,
so anything drawn at all is visible — once with /Filter /JBIG2Decode and once
with no filter, and requires the first to draw nothing and the second to draw.
Against the parent commit the first fails with "drawn = true, want false".

100% statement coverage, go vet clean, nine cross-compile targets.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 475f700 into main Aug 27, 2026
1 check passed
@tannevaled tannevaled mentioned this pull request Aug 27, 2026
tannevaled added a commit that referenced this pull request Aug 27, 2026
reader v0.5.0 decodes /CCITTFaxDecode. 67 of the 1 633 real forms in the corpus
carry a fax and 6 of their pages have nothing else on them, so those pages drew
blank; requiring an older reader here would leave them blank for anyone who
asked only for this package, since minimum version selection gives them the
version this go.mod names.

fax_test.go guards it with a fax rather than a version string: one Group 4 row,
three white pixels then five black, coded in horizontal mode and built in the
test so nobody else's scan enters the repository. Against reader v0.4.2 it fails
with "the black part of the fax is not black: (6,4) = 255,255,255,255".

Measured through this package over the first page of all 1 633 real forms, 69
pages change: one from blank to drawn (fr-cerfa/cerfa_11818, 0 inked pixels to
28 989), fourteen with more ink, and fifty-one with less — those were showing
their own compressed bytes as a stencil, which #20 stopped and this finishes.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant