Skip to content

v0.52.0 — find and remove content drawn outside the page

Choose a tag to compare

@KenM76 KenM76 released this 11 Sep 04:07
· 6 commits to main since this release

Moving something off the sheet is not deleting it

A page box (/CropBox, or /MediaBox when there is none) is what a reader
displays. A content stream may draw anywhere. Marks outside the box are
still in the file: they print on a larger sheet, they survive a page-box
change, they reappear the moment somebody crops differently, and text among
them is still extractable and searchable.

Two new commands find that content and take it out.

Find it

pdfcer scan-offpage <files|folders…> [--recursive] [--tolerance PT]
                    [--detail | --files-only] [-o report.txt]

Files, folders, or a whole tree. Every file and every page is scanned
finding something does not stop the walk, and neither does a file that will
not open (that one is reported and the scan continues).

The exit code is 0 when nothing was found and 1 when something was, so
a script can branch on it. That is a verdict on the whole run, delivered at the
end.

For one log of everything in a single pass:

pdfcer scan-offpage R:/Products --recursive --detail -o report.txt

--files-only instead prints one path per affected file, which is the form
that pipes into a copy or a batch.

Measured on 341 real engineering drawings: 176 of them draw outside the
sheet
— 554 pages, 471,840 objects entirely off-canvas, 1,152 crossing the
edge. One sheet carried 15,927 off-page objects: an entire second drawing
parked to the left of the page.

Remove it, keeping what is on the page

pdfcer redact-offpage <files|folders…> [--recursive]
                      (-o FILE | --out-dir DIR) [--suffix -offpage]
                      [--force] [--dry-run]

Objects wholly off the page are dropped. Objects crossing the edge are cut
at the edge
, so the part on the sheet is kept — a line that runs off the
page keeps the segment that was on it, a text run keeps the glyphs that were
visible, an image keeps the samples inside the box.

That is redaction machinery, not a clip: the off-page bytes are removed from
the content stream rather than hidden, because a clipped path is a path whose
data survives. The same code cuts at the page edge that cuts at the edge of an
operator's redaction rectangle — one behaviour, not two.

Batch output mirrors the input tree under --out-dir rather than
flattening it: two product folders can hold drawings with the same file name,
and a flat folder would silently make one of them the other. An existing
output is skipped and counted unless --force, so an interrupted batch
resumes.

⚠️ Destructive and deliberate. Keep the input; --dry-run first.

The tolerance, and what it does not do

A border stroked exactly on the page boundary overhangs by half its line
width. Reporting that would bury a real finding — a title block sitting in the
margin — under thousands of edge-touching strokes, so the default ignores a
0.25 pt fringe. Raising --tolerance does not find less; it looks less.

A file it cannot read is reported, never counted clean

"Nothing off-canvas" and "I could not look" are different answers and do not
print the same way.


Also in this release: everything from v0.51.0 forward is unchanged; this is
Pass 294.0 and 294.1 on top of it.

Verified: end to end on one of the operator's own drawings — 9 pages, 234
paths dropped, 247 paths cut, 4,642 off-page glyphs removed; the output
re-scans clean and page 1 renders pixel-identical to the input. CI green at
the tagged commit.