Scanned scores are black ink on white paper stored as 8-bit greyscale or RGB, which costs several times what the same page costs as a bilevel image. Across an 11-song corpus this is 27.6 MB to 7.7 MB; Engel's bundle goes from 5997 KB to 2092 KB with byte-identical slices, since only the archived copy changes. Three approaches were measured and discarded first, which is worth recording because two of them are the obvious ones. Converting RGB to greyscale and re-encoding makes these files 20-86% LARGER: the source JPEGs are already near 0.7 bits per pixel, so re-encoding adds generation loss and spends more bits than the original did, and dropping chroma recovers nothing because JPEG already subsamples it. Lossless structural optimisation gains 0.1%, because images are 99% of every file and there are no duplicates. Downsampling works but 300 DPI is print resolution, and the PDF exists to be printed. Two failure modes were found by looking at output rather than at byte counts, and both are now refused: - A scan at ~115 DPI came back with broken staff lines. Guarded on resolution as the image is *placed on the page*, so a tiled scan with 126 small images still qualifies where a pixel count would reject it. - Cover artwork was flattened to grey. Guarded on chroma: artwork measures 44% off-grey against 3% for sensor tint on a greyscale scan. The first threshold of 2% was a false positive that cost 685 KB on one song for nothing; 10% sits in the gap with room either side. Exposed as a button rather than a checkbox. It reports what it skipped and why, and shows a before/after crop, because the failure it can produce is obvious at a glance and invisible in a size figure. Off by default: this is lossy on the copy kept for printing.
noteman-slicer
Turns a score PDF into the ordered slice images noteman consumes, plus the navigation markers that sit on them.
A slice is one system — one full line of music across all voices, typically 4–12 bars with lyrics intact. noteman displays them as a continuous vertical scroll, so the slicer's job is to cut a printed page into systems, clean them up enough to read on a tablet, and tag them with the score's navigation symbols.
Status: design only. No code yet. The design is settled; see below.
How it works
Open a PDF, and the tool proposes cuts between systems, a skew correction, and a content rectangle. You correct all of it — source quality varies too much for unattended processing, so detection is an accelerator that nothing depends on being right. You mark the header and footer regions discarded, set black and white points until the paper disappears and the notes go solid, place the rehearsal letters and jump markers, fill in the title block, and export.
Out comes one zip: the slices in order, their markers, the original PDF, and the song metadata. That bundle is the only channel to noteman — there's no API between the two tools.
Erasing previous-owner pencil marks, chord letters and breath marks stays in GIMP. That's the irreducible manual part, and GIMP with a stylus is already good at it.
Installation
Not yet installable. When it is:
uv tool install --editable .
That puts a noteman-slicer command on PATH which runs from any directory — no venv to
activate. Dependencies (PyMuPDF, PySide6, OpenCV, numpy) are all wheels; nothing
needs a system package.
Documentation
| CONTEXT.md | Glossary. What a slice, cut, discard, bundle and song scale actually mean here. Start here. |
| docs/spec.md | The specification: pipeline, geometry model, detection, editor, bundle format, and what noteman has to change. |
| docs/bundle-format.md | The Score Bundle Format — a standalone specification of the export format, independent of this tool. |
Deferred work is tracked as issues and milestones on the Gitea repo, not in this tree.
Decisions that were expensive to reach, each with the evidence behind it:
| ADR 0001 | The slicer owns all image processing; the bundle is the only channel to noteman. |
| ADR 0002 | Raster only in release 1 — measured SVG slice sizes and what they showed. |
| ADR 0003 | Lossless WebP beats every lossy option and every alternative format here. |
| ADR 0004 | No unattended mode: detection suggests, a human confirms. |
| ADR 0005 | PyMuPDF for all PDF access, accepting AGPL. |
| ADR 0006 | Systems are found by vertical brackets; row-darkness gaps get it wrong. |
| ADR 0007 | A project is spent once exported; reopening starts fresh. Reverses an earlier decision. |