The pdf module is the whole of M1 except the debug overlay, which needs
detection results to draw.
Source type is detected per PDF by looking for a page-covering image,
and is always reported for confirmation rather than applied silently
(ADR 0004). Rasters are extracted via Pixmap(doc, xref) rather than by
decoding extract_image() bytes, because MuPDF handles JBIG2 and CCITT
scans that no image library will.
Scanned pages are extracted at the embedded image's native resolution;
only vector pages are rendered, at 600 DPI. Verified against the corpus:
Elaman nalka (vector) renders 4959x7017, Ketun joululaulu (scan) loads
1653x2332, Engel (scan) 2552x3504 — and Engel's page 2 is 2480 wide
where page 1 is 2552, so scan width varies within one PDF.
tests/test_pdf.py builds its own PDFs so the check runs without corpus
files, which are copyrighted and gitignored.
Closes#1, #2, #3
Page 1 of Engel (Bosse/Partitura) has a boxed VERSE 1 label in the left
margin at the same rows as the preceding system's bass lyric line — ink
on both sides of the page throughout the band, so no horizontal line
separates them. The label belongs to system 2, the lyrics to system 1.
A cut is therefore a polyline spanning the page, two points being the
ordinary straight case. A slice bounded by a non-straight cut is not
rectangular: its image is the region's bounding box with everything
outside made transparent, which composites invisibly on the viewer's
sheet. Masking paints transparency, never white.
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).
Records the outcome of the design review that reworked the original
handoff notes:
- CONTEXT.md — ubiquitous language for the slicer (slice, cut, discard,
content rectangle, trim, song scale, bundle, project, jump source)
- docs/adr/0001 — the slicer owns all image processing and the bundle is
the only channel to noteman; noteman's sharp pipeline goes away
- pyproject renamed to noteman-slicer
- .gitignore keeps scores and bundles out of the repo (copyright, size)