Cropping a PDF does not delete anything
You crop the letterhead off a PDF, the page looks right, and you send it. The text you cropped away is still in the file — every byte of it, in the same place, drawn at the same coordinates. Cropping moved the window, not the content.
The check that gives a false all-clear
Most people who worry enough to check run something like strings report.pdf | grep -i confidential, get nothing back, and conclude the crop worked. It didn't. Page content in a PDF is a Flate-compressed stream, and the text inside it is frequently written as hexadecimal rather than ASCII — a line reading CONFIDENTIAL-PAYROLL is stored as <434F4E464944454E5449414C…> Tj, inside a deflate block. strings cannot see through either layer, so it reports exactly what you hoped to hear.
That is what makes this trap durable. The naive check does not merely fail to find the problem; it actively confirms the wrong answer.
Two commands that show the truth
qpdf can rewrite a PDF with its streams uncompressed and its structure laid out in readable form:
qpdf --qdf --object-streams=disable cropped.pdf cropped.qdf
grep -a 'Tj' cropped.qdf | headThe drawing instructions are all there, including the ones for content that now sits outside the visible window. If the text comes back as hex, decode it: echo 434F4E464944454E5449414C | xxd -r -p. Run the same two commands on the original and diff the page's content stream against the cropped one: they are identical, byte for byte. Only /CropBox changed.
We assert exactly that in this project's own test suite rather than claiming it: the pdf-crop tests draw a line of text at the top of a page, crop 100 points off that edge, decompress both content streams, and require them to match — while the visible height drops from 800 to 700. A warning nobody verifies is just a disclaimer.
Why: the window and the drawing are different things
A PDF page carries a /MediaBox (the sheet) and optionally a /CropBox (the region a viewer should display). Cropping tools set the CropBox. The content stream — the actual sequence of drawing operators — is untouched, because editing it would mean re-flowing text, re-mapping fonts and rewriting positions, which is a different and far harder operation.
So the crop is a viewing instruction, and every consumer that ignores it sees everything: text extractors, indexers, converters, anyone who opens the file with a library instead of a reader, and anyone who simply sets the CropBox back.
What actually removes it
Render the page to pixels and rebuild the document from those pixels. The cropped-away region is never drawn into the raster, so it cannot survive:
- Crop to the region you want to keep.
- Render each page to a PNG — the visible window becomes an image.
- Reassemble the images into a PDF.
The cost is real and worth stating: the text is now pixels. It cannot be selected, searched, copied or read by a screen reader, and the file is usually much larger. That is a genuine loss, not a footnote — but it is the trade that actually removes the content, and choosing it knowingly beats believing a crop did the job.
The same trap, three doors down
Drawing a black rectangle over text is the identical failure with better marketing: the rectangle is one more drawing instruction on top of the text, and the text underneath is extracted as cleanly as ever.
Metadata is a separate channel. Author, title, producer and the XMP packet travel with the file and survive any amount of visual editing — read and clear them explicitly. Note that a document can carry its metadata twice, in the info dictionary and in XMP, and newer readers prefer the copy you did not edit.
Cropping an image is not the same operation. Cropping a raster image really does discard the pixels outside the rectangle — there is no window-versus-content distinction to hide in. The two tools share a name and not a behaviour, which is precisely why our pdf-crop page says “cropping hides the content; it does not delete it” and the image one does not.
What we do not do
True redaction — removing the text under a black box while keeping the rest of the document as text — requires rewriting content streams. We do not implement it, and we would rather say so than ship something that looks like redaction and is not. If your document is genuinely sensitive, treat the rasterise-and-rebuild route above as the floor, verify the result with the qpdf commands rather than with strings, and remember that the file's history lives in its metadata too.