Files
Copies/docs/crop_blank_margins.md

4.5 KiB

Scanned PDF margin cropping

Copienator has one automatic crop detector. It finds strongly coloured or dark ink, recovers nearby weaker strokes, and removes substantial blank areas above and below the detected content. It is designed for scanned student work on plain, lined, or gridded paper, including mildly skewed pages and recurring punched-hole artifacts.

Review utility

Run from the repository root:

python -m copienator.crop_blank_margins Interro01/Copies tmp/cropped-copies

The input can be a directory or one PDF. Directory processing includes only PDFs directly inside that directory. The utility writes processed PDFs, an HTML comparison gallery, JPEG previews, and JSON/CSV reports into the output directory. Source PDFs are never modified.

Available options:

  • --dpi 200: analysis resolution.
  • --padding-mm 6: space retained around detected content.
  • --min-crop-mm 5: minimum worthwhile removal at either edge.

The output retains filenames, page order, page count, colour, rotation, and the embedded scan data. Cropping changes the PDF CropBox rather than rasterizing the page. Red shading in index.html shows the removed part of each original page. A review-* status records uncertainty; one edge can still be cropped while the other remains unchanged.

Detection

The detector uses colour and darkness as strong ink seeds. It recovers connected weak strokes within a 2 mm neighbourhood using directional contrast, which limits growth along paper lines. Two seed thresholds are compared so unstable boundaries can be flagged for review.

For dark neutral paper, it deskews the scan and confirms repeated horizontal or vertical ruling before suppressing paper-line pixels. It uses short directional openings to tolerate broken or bent grid lines. Very dark fraction bars and diagram axes remain protected. Repeated components with similar size and alignment in the outer 15 mm are treated as punched holes only when at least three span a substantial part of the page. Writing in the same side column still protects its margin.

On confirmed ruled paper, faint sparse strokes in the central 80% of the page use a moderately more sensitive component filter. The outermost 9% on each side uses a stricter filter because punched holes, torn binding edges, and page numbers normally appear there.

The large-blank refinement changes an edge only when it finds at least 30 mm of additional empty paper. A 2 mm recovery neighbourhood is applied before the normal padding. Apparently blank pages and pages without reliable ink seeds are kept at full height.

This remains a heuristic. Extremely faint isolated pencil marks, unusually damaged ruling, and repeated handwriting shaped like hole artifacts can be ambiguous. Review crops before generating answer coordinates.

Optional GUI step

After Séparer et réordonner les pages, the GUI offers Rogner les zones vides. It can process the whole evaluation or a selected PDF. It runs at 200 dpi with 6 mm padding and uses five worker processes by default. The CLI form is:

python -m copienator crop-margins EVALUATION --workers 5

The batch is fully prepared before any source is replaced. Detection failures and interruptions leave the working PDFs intact; replacement errors roll back. Each successful run saves the untrimmed PDFs and its report under .copienator/runs/crop-margins-*/. The Archivage step removes these backups and reports while keeping the cropped copies and execution logs.

Cropping must run before label detection. If a selected PDF already has a same-named JSON coordinate file, the command stops before changing any PDFs. When ALWAYS_CROP is true in config.py, this facultative step starts automatically when first reached; the default configuration keeps it manual.

Performance

Separate worker processes isolate MuPDF and each worker uses one OpenCV thread. The detector uses native channel operations, vectorized component filtering, cached separable background filtering, and a coarser Hough voting step for skew candidates. Report rows remain ordered by copy and page regardless of worker completion order.

On the Ryzen 7 PRO 7840U, an end-to-end benchmark took 56.48 seconds for 48 PDFs of 10 pages, including rendering, detection, PDF writing, backups, and replacement. The fixture uses Interro01 and DS08VA scans and cycles pages in shorter copies, so it does not contain 480 distinct scans. Runtime depends on the CPU, storage, and scan content.

Run the focused checks with:

python -m unittest tests.test_crop_blank_margins tests.test_ink_detection tests.test_crop_margins_command -v