"""Command line entry point.""" from __future__ import annotations import argparse import sys import numpy as np from pathlib import Path from . import __version__, overlay from .detect import detect_page from .pdf import SourceType, open_source, page_raster def _info(args: argparse.Namespace) -> int: source = open_source(args.pdf, SourceType(args.type) if args.type else None) note = f" (detected {source.detected.value}, overridden)" if source.overridden else "" print(f"{source.path.name}: {source.type.value}{note}, {len(source)} pages") for i in range(len(source)): h, w = page_raster(source, i).shape print(f" p{i + 1:<3} {w}x{h}") source.close() return 0 def _detect(args: argparse.Namespace) -> int: source = open_source(args.pdf, SourceType(args.type) if args.type else None) out = Path(args.out) out.mkdir(parents=True, exist_ok=True) pages = range(len(source)) if args.page is None else [args.page - 1] for i in pages: gray = page_raster(source, i) detection = detect_page(gray) staves = [s.staff_height for s in detection.systems if s.staff_height] note = f", staff {np.median(staves):.0f}px" if staves else "" print( f"p{i + 1:<3} skew {detection.skew:+.2f}° " f"{len(detection.systems)} systems{note}" f"{' (no bracket)' if detection.bracketless else ''}" ) for n, system in enumerate(detection.systems, 1): print(f" sys{n}: {system.top}–{system.bottom} h={system.height}") overlay.write(gray, detection, out / f"{source.path.stem}-p{i + 1:02}.png") print(f"overlays written to {out}/") source.close() return 0 def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser( prog="noteman-slicer", description="Cut score PDFs into noteman's slice images and markers.", ) parser.add_argument("--version", action="version", version=__version__) sub = parser.add_subparsers(dest="command", required=True) info = sub.add_parser("info", help="classify a PDF and report its page rasters") info.add_argument("pdf") info.add_argument( "--type", choices=[t.value for t in SourceType], help="override source-type detection", ) info.set_defaults(func=_info) det = sub.add_parser("detect", help="run detection and write debug overlays") det.add_argument("pdf") det.add_argument("--out", default="overlays", help="output directory") det.add_argument("--page", type=int, help="single 1-based page instead of all") det.add_argument("--type", choices=[t.value for t in SourceType]) det.set_defaults(func=_detect) args = parser.parse_args(argv) return args.func(args) if __name__ == "__main__": sys.exit(main())