DEVTOOLBOX / GUIDES this guide
PDF workflow order: page operations, content operations and the edits you cannot undo
Most PDF damage is ordering damage: text is extracted after a flatten, a watermark is added before a crop, a JPEG is re-encoded once per pass. This guide separates page-level work from content-level work, puts a number on what each pass costs, and marks the three operations that cannot be reversed. Every section ends with a criterion you can apply to the file in front of you.
Two PDF families: text-based and scanned, and why every workflow starts there
Every PDF decision starts with one question: does the page hold text objects, or one bitmap? ISO 32000-1:2008 (PDF 1.7) and ISO 32000-2:2020 (PDF 2.0) describe the same container: numbered objects, a cross-reference table, and a page tree whose leaves carry a content stream plus a resource dictionary. A generated file puts text-showing operators and font dictionaries into that stream. A scan puts a single image XObject there instead, filtered by DCTDecode for JPEG, JPXDecode for JPEG 2000, CCITTFaxDecode for Group 3 or Group 4 fax, or JBIG2Decode.
Confirm the family in five seconds, before opening any tool. Select three words in a viewer: a clean selection means a text layer exists. If nothing selects, look for font dictionaries in the page resources; no fonts means pixels only. Size per page corroborates it. An A4 page at 300 dots per inch is 2480 by 3508 pixels, so a compressed scan lands in the hundreds of kilobytes, while a page of text usually stays in the tens.
The two families fail in opposite directions, and that decides the path. Text-based pages survive extraction but may not survive editing: a subset font without a ToUnicode CMap maps glyph identifiers rather than characters, so extraction returns substitution garbage that no setting repairs. Scanned pages survive every page operation, because merge, split, rotate and crop copy streams without decoding them, yet they yield no text until OCR runs. The irreversible point sits between the two. Rasterizing a text page deletes its text layer for good, and an OCR layer laid over a scan is a guess that looks authoritative, with accuracy unknown unless the tool reports confidence per word.
| Family | How to confirm it | What works immediately | What is missing |
|---|---|---|---|
| Generated text | Text selects and copies cleanly | Extraction, reflow, form edits | Nothing, until someone rasterizes |
| Plain scan | No font resources, one image per page | Page operations, crop, OCR | No text at all until OCR runs |
| Searchable scan | Text selects, glyphs match the image | Search and extraction, with OCR error | The true text layer, already replaced |
| Vector export | Text selects, edges stay sharp at any zoom | Extraction and printing | Nothing, while fonts stay embedded |
One test decides the whole plan: select a word, and see whether the file has characters or only pixels.
Page operations versus content operations: what each one rewrites
Page operations rewrite the page tree; content operations rewrite the page content. The page tree of ISO 32000-1 section 7.7.3 is a /Pages root with /Kids and /Count, and leaves that name a /MediaBox and a /Contents stream. Merging, splitting, deleting, reordering, rotating and cropping all edit that tree or the boxes on its leaves, and they copy content-stream bytes untouched. Watermarking, numbering, form filling, flattening, OCR and redaction change what is painted, by appending a stream, adding a resource, or rewriting operators in place.
Cost follows from that split, not from the tool. A copy-only operation cannot degrade an image, because no filter is ever decoded, so rotating a thousand pages takes seconds. Any operation that appends to /Contents usually decodes and re-encodes the stream with FlateDecode, the zlib wrapper of RFC 1950 around deflate from RFC 1951. That pair is lossless: text and vector paths return byte for byte. An embedded JPEG does not, because the image XObject is decoded through DCTDecode and re-encoded, so a well-built tool copies it as a separate object and leaves it alone.
Reversibility depends on whether the change is separable. Rotation writes a multiple of 90 into /Rotate, so three more rotations restore the page. A watermark appended as its own element of the /Contents array can be dropped later; the same watermark painted into the existing stream cannot be separated from the text without editing operators by hand. Choose the separable form whenever a later revision is plausible. Treat flattening as a one-way door: it folds widget and annotation appearances into page content, so the fields are gone even though the visible marks survive as vectors.
| Operation | Structure rewritten | Re-encode risk | Undo |
|---|---|---|---|
| Rotate 90 | /Rotate on the page dictionary | None | Yes, three more turns |
| Reorder or delete | /Kids and /Count in the page tree | None, streams are copied | Only from the original file |
| Crop | /CropBox, leaving /MediaBox | None | Yes, widen the box again |
| Watermark | A new stream in /Contents | Flate on the page stream | Yes, if it stays separate |
| Flatten | Appearances into page content | Depends on the source filter | No, widgets are consumed |
| Rasterize | The page becomes one image | Lossy at the chosen rate | No, text is gone |
Sort the planned steps by this column: everything copy-only is safe, and everything below it is a decision.
Cropping is not redaction, and flattening is not compressing
A page has five boundaries, and the crop operation moves one of them. /MediaBox is the physical page, /CropBox is the region a viewer displays and prints, and /BleedBox, /TrimBox and /ArtBox record production intent. All are rectangles in default user space, where one unit is 1/72 inch, and anything outside /MediaBox is intersected away. Cropping sets that one rectangle. Nothing is deleted: text outside the box still extracts, still occupies bytes in the file, and returns the instant anyone widens the box or opens the file in a viewer that ignores it.
So cropping is the right tool for margins and the wrong tool for confidentiality. Redaction is the operation that removes: it rewrites the content stream so glyphs and the image pixels beneath are gone, which is irreversible and has to be verified afterwards by extracting text again from the redacted region. The common failure is a black rectangle, either an annotation or a filled path in the stream, drawn over a visible name. It looks redacted, prints black, and hands the name to anyone who selects the text. Verify by copying, never by looking.
Flattening and compressing share a menu but do different jobs. Flattening converts interactive appearances into plain page content: the file renders identically everywhere and stops accepting input, the vector data usually stays vector, and output often grows because appearance streams were stored separately and compressed. Compressing re-encodes streams and can shrink a file without changing structure, but only FlateDecode and the ASCII filters are lossless. DCTDecode and resampling discard detail, and a default that downsamples to 150 dots per inch is the most damaging default in the format.
| Action | What actually changes | Size effect | Is the content still there |
|---|---|---|---|
Tighten /CropBox | Visible region only | None, no bytes removed | Yes, fully intact |
| Black box over text | One drawn annotation or path | Grows slightly | Yes, and it always was |
| Redaction | Glyphs and pixels removed | Shrinks | No, and it is the point |
| Flatten | Appearances become page content | Often grows | Marks stay, fields do not |
| Flate re-encode | Same data, tighter coding | Usually shrinks | Yes, lossless |
| Downsample to 150 dpi | Resampled image samples | Shrinks a lot | No, detail is discarded |
Two rows here look alike in a viewer and differ by everything that matters: one hides, the other deletes.
Merging and splitting: bookmarks, forms and page labels that get lost
A PDF carries two kinds of state. Page-level state travels with the page: its content stream, resources, annotations and boundaries. Document-level state exists once in the catalog: /Outlines for bookmarks, /PageLabels for printed numbering, /AcroForm for fields, /Names for named destinations and embedded files, /Metadata for the XMP packet defined by ISO 16684-1. Merge produces exactly one catalog, so every structure in that second list survives from one input, normally the first, and the rest disappear without any warning to the operator.
Page labels are the loss that hurts quietly. A report numbers front matter i to iv with a /PageLabels range using the /r style, then restarts arabic numbering for the body with /St. Merge ten such files and the ranges normally come from the first file, so the printed number and the viewer index diverge and a citation to page 47 lands somewhere else. Check it on the thumbnails after any merge: when a page shows 12 and the viewer reports 138, the labels were reduced to a single range or dropped entirely.
Splitting has the mirror problem: bookmark entries and named destinations that pointed across the cut become dangling references, meaning links that render normally and do nothing. Fields fail in a third way. /AcroForm field names must be unique across the tree, so merging two copies of one form produces two widgets with the same fully qualified name, and filling one fills both. Flatten before merging when the forms are already filled, or rename fields when they must stay editable. Expect linearization to be void as well: the hint tables of ISO 32000-1 Annex F describe the original byte layout, and any edit invalidates them.
| Structure | After a naive merge | After a naive split | Cost paid |
|---|---|---|---|
/Outlines | Kept from the first file only | Entries pointing outside dangle | Rebuild or remap by hand |
/PageLabels | One range applied to every page | Ranges restart or vanish | Printed number stops matching the index |
/AcroForm fields | Duplicate names collide | Values stay with their own part | Flatten or rename before merging |
/Names destinations | Later destinations lost | Cross-part links break silently | Links look right and do nothing |
/Metadata XMP | One identity for the whole output | Every part claims the whole | Title and page count are wrong |
| Linearization | Hint tables invalid | Hint tables invalid | Progressive display lost |
Document-level structures are singletons, so the arithmetic of merging is subtraction for all but one input.
Converting to images and back: what resolution actually costs
Resolution is not stored in a PDF; it is a consequence of two numbers. Default user space has 72 units per inch, so pixels equal points divided by 72, multiplied by the chosen dots per inch. A4 is 595.28 by 841.89 points, which at 300 dots per inch gives 2480 by 3508 pixels, or 8.7 megapixels per page. Multiply by bytes per pixel: three for RGB, one for grayscale, one bit for bilevel. One A4 page costs 26.1 MB as raw RGB, 8.7 MB as grayscale, and 1.1 MB as a 1-bit image before any filter.
Choose the rate from the consumer, not from the source. Text a human will read, or an OCR engine will parse, needs 300 dots per inch: a lowercase x at a 10 point size is roughly 5 points tall, so 300 dots per inch renders it about 21 pixels high, enough for reliable glyph classification, while 150 gives about 10 pixels and loses accuracy on small type. Screen-only reference tolerates 150. Upsampling recovers nothing, because area scales with the square of the linear factor: converting at 150 and resampling to 300 quadruples the bytes and adds no detail.
The return trip is where geometry breaks. An image has pixels and a PDF page needs a size, so something must supply the rate. A tool that divides by 300 turns 2480 pixels into 595 points, a correct A4. A tool that assumes 72 turns the same image into a page 34.4 inches wide, and one that assumes 96, the CSS ratio, produces 25.8 inches. Content is one-way regardless: text becomes pixels, OCR may guess a layer back, but fonts, vectors and links never return. Keep the generated original and treat the image as a rendering of it.
| Dots per inch | A4 page in pixels | Raw RGB per page | Reasonable use |
|---|---|---|---|
| 72 | 595 by 842 | 1.5 MB | Thumbnail only, text unreadable |
| 150 | 1240 by 1754 | 6.5 MB | On-screen reading, no OCR |
| 300 | 2480 by 3508 | 26.1 MB | Print and OCR baseline |
| 600 | 4961 by 7016 | 104 MB | Line art, four times the data |
Pixels and bytes follow from one multiplication, so the cost of a plan is known before it runs.
Extracting text: why the order comes out wrong
A content stream is a program, not a document. Operators place glyphs through text matrices, with Tm, Td, TD and T*, and their sequence in the stream is painting order, which the specification defines; it says nothing about reading order. A generator that emits a two-column page line by line across both columns produces a stream where adjacent runs belong to different sentences. An extractor therefore reconstructs order from geometry: it sorts by vertical position, then by horizontal position, and inserts spaces where the gap between glyphs exceeds a threshold.
Each heuristic has a failure mode. Words are often positioned by moves rather than by space characters, so a run without a space glyph needs inferred spacing, and a justified line has variable gaps that a fixed threshold splits wrongly. Ligatures arrive as single code points, U+FB01 for fi, and need normalization under Unicode UAX #15 to decompose. Headers, footers and footnotes share the coordinate space of body text and get interleaved. Hyphenation leaves the halves as separate runs, so a word broken across a line keeps its hyphen unless the extractor joins them back.
The deeper limit is the character mapping. Extraction needs a glyph-to-Unicode table from the /ToUnicode CMap, and when a subset font omits it, only glyph identifiers or Adobe glyph names remain, producing plausible Latin nonsense that no post-processing repairs. Tagged PDF is the one structural answer: /StructTreeRoot of ISO 32000-1 section 14.7 records logical order, and PDF/UA (ISO 14289-1) requires it for accessibility. If order matters and the file is untagged, return to the source document, because a PDF was built to preserve appearance, not text.
| Symptom in the output | Cause | Fix or verdict |
|---|---|---|
| Columns interleaved | Generator emitted lines across both columns | Extract per column or with layout preserved |
| Words run together | No space glyphs, only positioned runs | Tune the gap threshold, then accept leftovers |
| fi arrives as one character | Ligature stored as U+FB01 | Normalize with NFKC under UAX #15 |
| Digits wrong, letters fine | OCR confusion of 1 and l, 0 and O | Re-OCR at 300 dpi, then verify every number |
| Chinese text is garbage | CID font without a ToUnicode CMap | Unrecoverable, go back to the source |
Diagnose by shape: geometric symptoms yield to tuning, mapping symptoms do not.
An order of operations that avoids re-encoding twice
Budget passes, not steps. Every pass over a file falls into one of four cost classes: copy-only, which moves bytes and cannot degrade anything; lossless re-encode with Flate, which costs time and keeps bytes; lossy re-encode of an image, which compounds with each pass; and rasterization, which ends the life of the file as text. Sorting a plan into those classes gives the order, and the rule is to run each class once, as one batch, rather than once per requirement.
The sequence follows from that rule. Extract text and metadata first, while nothing has been painted over the source layer. Then run the page operations in a single command: delete, reorder, rotate, crop. They are copy-only and cheap, and cropping fixes the visible box that later content must fall inside. Rotate before crop, because /CropBox is expressed in unrotated default user space, so a box calculated after a 90 degree rotation describes the wrong side of the page. Add watermarks and page numbers once the box is settled, as their own elements of the /Contents array so they stay removable.
Rasterize only when the requirement is truly pixel-level, such as removing something that sits inside an image, and treat it as the last irreversible action. Optimize after all edits in a single pass, and accept downsampling only when the loss is intended. Sign, then encrypt, at the end: a signature covers a byte range, so any later write invalidates it, and encrypting early forces every intermediate tool to decrypt and re-encrypt, which under ISO 32000-2 means AES-256 and a fresh file key instead of the parameters you chose.
| Step | Why it belongs here | Cost of doing it late |
|---|---|---|
| Extract text and metadata | Source layers are still clean | Watermarks and OCR pollute the output |
| Delete, reorder, rotate | Copy-only, no filter decoded | Positions and boxes already baked in |
| Crop | Sets the box for everything painted later | Later content lands outside the crop |
| Watermark, page numbers | Placed inside the final visible box | Second pass to reposition or clip |
| Fill fields, then flatten | Widgets are still interactive | Nothing left to fill, form rebuilt |
| Redact or rasterize | Last irreversible action | No text left for extraction |
| Sign, then encrypt | Any later byte change breaks the signature | Re-signing after every edit |
Read top to bottom: each class of work runs once, and the irreversible ones are last.
Frequently asked questions
- Does cropping a PDF delete what sits outside the box?
- No. Cropping writes a smaller
/CropBoxand leaves every byte of the content stream in place, so hidden text still extracts, and widening the box or using a viewer that ignores it brings the content straight back. Use cropping to fix margins, trim marks and print area. For confidentiality you need redaction, which rewrites the stream, and a full rewrite that leaves no incremental update holding the original stream. - Why do bookmarks disappear after merging?
- Bookmarks live in
/Outlines, which exists once per document, and a merged file has one catalog, so it keeps the outline of whichever input supplied the catalog and drops the others. Page labels and named destinations go the same way, without a warning, while the pages themselves look correct. Rebuild the outline after the merge from printed page numbers or a heading list, then compare page labels against the viewer index. - Can I trust OCR text, and does it alter the scan?
- OCR adds a text layer, usually painted in render mode 3 so it is invisible, and leaves the page image untouched, so the operation is additive and the original scan survives inside the same file. The layer is a guess: at 300 dots per inch clean printed prose is reliable, while digits are not, because 1 and l, 0 and O, 5 and S are the usual confusions. Verify every number you intend to quote.
- Should I flatten a form before sending it?
- Flatten when the recipient only has to read it, since flattening removes the interactive widgets and guarantees identical rendering on any device. Never flatten while the file still needs edits: appearances fold into page content and the fields cannot be restored without rebuilding the form. If you flatten first and then keep editing, every later change becomes another pass over an already rendered page.
- Does a permissions password stop text from being copied?
- Not reliably. The owner password sets flags in the encryption dictionary, and the specification leaves enforcement to the reader, so many libraries and non-Adobe tools ignore the flags and extract the text anyway. If text must not leave the document, remove it: redact the stream, or rasterize the page and accept the permanent loss. Encryption in PDF 2.0 means AES-256, and the user password controls whether the file opens at all.