Skip to content

Hand a page over as a JPEG, GIF, TIFF or BMP as well as a PNG - #24

Merged
tannevaled merged 1 commit into
mainfrom
hand-over-other-formats
Aug 30, 2026
Merged

Hand a page over as a JPEG, GIF, TIFF or BMP as well as a PNG#24
tannevaled merged 1 commit into
mainfrom
hand-over-other-formats

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

The Read group could draw a page and hand it over one way. gfx's
codec.Encode writes five formats, and now all five are offered.

The shape

A CycleButton on the same row as the verb it governs — the idiom the Pages
group already uses for Turn them — so the row it replaced stayed one row
and the tests that press the Read panel by position kept their
coordinates. readRows grew entries at the end; nothing shifted.

It governs the zip below it as well. Both verbs draw a page and write it, and
two choosers disagreeing about the same picture would be a question nobody
asked. A zip asked for as JPEGs holds JPEGs, under .jpg names.

Which formats are offered is asked of the library rather than guessed. The
table names every container codec can read, with the suffix a person
expects, and codec.CanEncode decides which reach the chooser — so a
reference encoder arriving in gfx (WEBP is the obvious one) puts that format
in front of a person with no line changing here.

drawnPNGdrawnPicture, encodePNGencodeImage(w, img, format),
pageAsPNGpageAsPicture. The old names would be lies.

What was measured, not just added

  • The bytes are sniffed, not trusted. Every offered format is selected by
    pressing the chooser on the drawn panel and the page handed over by pressing
    the verb beside it; page001.jpg has to sniff as JPEG. Size, ink and the
    wrap back round to PNG are checked with it.

  • The suffix table is checked against a list written out in the test, not
    against itself. That was not academic. The first version of the test passed
    with JPEG's suffix swapped for ".png", because the name and the bytes were
    both read from the same row — a table that is its own oracle proves nothing.
    It fails now.

  • Three more mutations, all caught: writing PNG whatever is chosen; naming
    the zip entries .png regardless of the choice; leaving the chooser's
    Subscribe unwired.

  • Alpha is gfx's business and is not redone here. What is checked is
    what arrives: every format comes back with no pixel below full opacity and
    more than half the page light — the paper is white, not the black a dropped
    alpha channel would leave. (Worth noting: render.Options.Background
    defaults to opaque white, so a whole page is opaque before it reaches the
    encoder anyway. The compositing matters for correctness of contract, not for
    this call site's pixels.)

  • A page that ran out of time is still handed over, with the status line
    saying so, in whichever format was chosen. The existing test keeps that.

  • Over 40 real arXiv documents, the first page of each drawn at twice the
    size it is shown at and written five ways: every file was named for what it
    holds, and the mean came to

    format mean bytes
    PNG 209 kB
    JPEG 129 kB
    GIF 105 kB
    BMP 4.9 MB
    TIFF 6.6 MB

The thing worth saying plainly

gfx writes TIFF and BMP uncompressed. tiff.Encode(w, img, nil) takes
golang.org/x/image/tiff's default, which is no compression; a page that is
209 kB as a PNG is 6.6 MB as a TIFF, thirty-two times larger. The ratio
between the two large ones is exactly 4 bytes a pixel against 3 — the alpha
channel TIFF carries and BMP does not — which is how one can tell it is the
raw raster and not something going wrong here. That is gfx's to change if it
ever is; this PR does not paper over it, and writes the numbers where somebody
choosing a format for a 200-page document will see them.

Separately: the README's Read bullet said nothing about handing a page
over at all, having been left behind by #15 and #21. It now describes what the
group does.

The gate

  • go test100.0% of statements
  • go vet ./... clean, gofmt -l . empty
  • GOOS=js GOARCH=wasm go build links
  • the browser check drives it in Chrome and returns PASS

🤖 Generated with Claude Code

The Read group could draw a page and hand it over one way. gfx writes five
formats, and which five is its own answer rather than a guess: the list here
names every container codec can READ, with the suffix a person expects, and
codec.CanEncode decides which of them reach the chooser. A reference encoder
arriving in gfx — WEBP is the obvious one — puts that format in front of a
person with no line changing here.

The chooser is a CycleButton on the same row as the verb it governs, the
idiom the Pages group already uses for "Turn them", so no row moved and the
tests that press the Read panel by row position kept their coordinates. It
governs the zip below it as well: both verbs draw a page and write it, and
two choosers disagreeing about the same picture would be a question nobody
asked. drawnPNG is drawnPicture, encodePNG is encodeImage taking a format,
and pageAsPNG is pageAsPicture, because the old names would be lies.

What was measured, not just added:

- Every offered format is pressed through the chooser on the panel and the
  bytes that come back are SNIFFED, not trusted: page001.jpg has to sniff as
  JPEG. Sizes, ink and the wrap back round to PNG are checked with it.
- The suffix table is checked against a list written out in the test rather
  than against itself. That was not academic: swapping JPEG's suffix for
  ".png" first left every check in the file green, because the name and the
  bytes were both read from the same row. It fails now.
- Three more mutations were run and all three fail: writing PNG whatever is
  chosen, naming the zip entries .png regardless, and leaving the chooser's
  subscription unwired.
- Alpha is gfx's business and is not redone here. What is checked is what
  arrives: every format comes back with no pixel below full opacity and with
  more than half the page light, so the paper is white rather than the black
  a dropped alpha channel would leave.
- A page that ran out of time is still handed over and the status line still
  says so, in whichever format was chosen.
- Over 40 real arXiv documents, the first page of each written five ways:
  every file was named for what it holds, and the mean came to 209 kB (PNG),
  129 kB (JPEG), 105 kB (GIF), 4.9 MB (BMP) and 6.6 MB (TIFF). The last two
  are uncompressed, and the ratio between them is exactly 4 bytes a pixel
  against 3 — the alpha channel TIFF carries. That is gfx's to change if it
  ever is, but it is written down where somebody choosing a format for a
  200-page document will see it.

100% of statements, go vet and gofmt clean, the js/wasm build links, and the
browser check drives it in Chrome and comes back PASS.

Also: the README's Read bullet had said nothing about handing a page over at
all, having been left behind by two earlier changes. It now describes what
the group does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit b1c7013 into main Aug 30, 2026
2 checks passed
@tannevaled
tannevaled deleted the hand-over-other-formats branch August 30, 2026 14:46
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