The handoff was written as a message to relay information; several decisions lived only there. Split into permanent homes: - docs/spec.md — scope, geometry model, pipeline order, detection, levels, editor, project file, markers, bundle format, noteman's changes, reference values - ADR 0002 — raster only in release 1; SVG slices measured at 40x WebP naive, 2.6x with a bounding-box cull, deferred on risk not size - ADR 0003 — lossless WebP with levels and 16-level alpha; every lossy option and alternative format measured larger for line art - ADR 0004 — detection proposes, the human disposes; no unattended mode - ADR 0005 — PyMuPDF for all PDF access, accepting AGPL - ADR 0006 — systems are found by vertical brackets, not row-darkness gaps, which miscount every page of a 6-voice score Also from testing against the hardest score in the repertoire: scanned PDFs carry their scan as an embedded image and must be extracted at native resolution rather than re-rendered at 600 DPI, and per-page deskew is mandatory (skew varies -2.6 to +1.2 within one PDF).
59 lines
2.6 KiB
Markdown
59 lines
2.6 KiB
Markdown
# Lossless WebP, with levels and alpha quantised to 16 levels
|
||
|
||
Slice images are encoded as **lossless WebP**, with the levels adjustment applied
|
||
and the alpha channel quantised to 16 levels. About 7 KB per slice, ~450 KB for a
|
||
65-system song. Every lossy option and every alternative format measured
|
||
*larger* for this content, which is the opposite of the usual intuition — hence
|
||
this record.
|
||
|
||
## The measurement
|
||
|
||
20 slices of one real song, levels applied throughout, relative to plain lossless
|
||
WebP:
|
||
|
||
| | vs baseline | |
|
||
|---|---|---|
|
||
| **WebP lossless + alpha quantised to 16** | **68%** | chosen |
|
||
| AVIF q60 | 90% | lossy, for 10% |
|
||
| WebP lossless | 100% | baseline |
|
||
| WebP lossy q85 (alpha) | 107% | |
|
||
| AVIF q85 | 114% | |
|
||
| JXL lossless | 130–133% | |
|
||
| WebP lossy q85 (opaque ink-on-white) | 158% | |
|
||
| PNG grayscale + alpha | 165% | |
|
||
| AVIF lossless | 188% | |
|
||
|
||
Separately, before levels: applying levels alone takes 338 KB → 211 KB, a 38%
|
||
reduction.
|
||
|
||
## Four results that contradict an instinct
|
||
|
||
- **Lossy is bigger than lossless here.** Not a quality problem — the measured
|
||
difference between q85 and lossless is max 12/255, mean 0.33, i.e. invisible.
|
||
Lossy VP8 simply spends more bits on sharp black/white edges than VP8L's
|
||
palette and predictor transforms do, and notation is nothing but sharp edges.
|
||
The "q85 looks fine" intuition comes from photographs and inverts here.
|
||
- **AVIF and JXL both lose**, AVIF lossless by nearly 2×. Their lossless modes
|
||
are afterthoughts on photo codecs. WebP's VP8L is close to purpose-built for
|
||
flat two-tone line art — sheet music is the content type it is best at. JXL
|
||
additionally has no path forward in Chrome.
|
||
- **Alpha costs nothing.** Opaque ink-on-white and black-plus-alpha are within
|
||
0.1% at lossless, so paper-tint removal and future non-rectangular slices are
|
||
free.
|
||
- **Levels is the single biggest lever** — 38%, as a side effect of a control
|
||
that exists for quality reasons anyway. Pushing the white point below the
|
||
paper's luminance sets vast regions to exactly `alpha = 0`, which costs almost
|
||
nothing to encode.
|
||
|
||
Alpha quantisation to 16 levels is imperceptible: antialiased edges span 2–3 px
|
||
at 1920, and 16 steps across that is below notice. 8 levels starts to gamble on
|
||
thin strokes.
|
||
|
||
## Rejected as not worth it
|
||
|
||
- **Encoder effort tuning** — Pillow's `method=6` buys 3% and a dependency.
|
||
- **`alpha_quality=60`** — 24%, for less control than quantisation gives.
|
||
- **Grayscale WebP** — no such mode exists. It wouldn't help anyway: the RGB
|
||
channels are constant black and compress to nearly nothing, so alpha is the
|
||
entire payload.
|