Micro Tool Yard logo
Tools

Blog

Why Merging PDFs Isn't Just Concatenation

Stitching two PDFs into one sounds like gluing files end to end, but page trees, resource dictionaries, and font name collisions make it a real merge problem.

Say the word "merge" to most people and they picture something like cat a.txt b.txt > c.txt — put file A's bytes first, file B's bytes after, done. PDFs almost never work that way, and the reason is worth digging into, because it explains a whole category of bugs that show up in badly-built merge tools: text that looks fine on page 3 but renders as boxes on page 9, file sizes that balloon for no obvious reason, or bookmarks that point to the wrong page after combining two reports.

Two independent object universes

Every PDF file has its own private numbering scheme for objects — object 1, object 2, object 3, and so on, each meaning something entirely different depending on which document you're looking at. Object 5 in invoice.pdf might be a Helvetica font descriptor; object 5 in report.pdf might be a JPEG of a bar chart. These numbers aren't globally unique identifiers — they're local addresses, valid only within the file that defines them, resolved through that file's own cross-reference table.

A merge tool has to take the page trees of both documents and combine them into a single new tree, which means every object reference inside every copied page has to be renumbered so nothing collides. If the merge naively kept both files' object numbers as-is, the combined file would have two different "object 5" definitions competing for the same slot, and every page from the second source that pointed to "object 5" expecting a font would instead get whatever the first document's object 5 happened to be — a chart, a color profile, garbage. Real merge implementations walk each source document's object graph, build a new file with a fresh unified numbering scheme, and rewrite every internal reference to match.

Fonts are where it gets genuinely tricky

The trickiest part of a PDF merge isn't the pages themselves — it's what the pages depend on. Two source documents both using "Arial" is a common, deceptively simple-looking case. Document A might have Arial embedded as a subset containing only the 40 glyphs it actually uses (a common space-saving trick: instead of shipping a full font with thousands of glyphs, embed just the ones the document needs, named something like ABCDEF+Arial with a random prefix to avoid exactly this kind of collision). Document B might embed a different subset,GHIJKL+Arial, with a different set of glyphs. If a merge tool got sloppy and tried to treat these as "the same font" because the human-readable name matches, pages from document B could end up referencing glyphs that were never embedded in document A's subset, and those characters would silently vanish or render as the wrong shape. Correct merge logic keeps each source document's font resources fully separate objects in the output, even when two fonts share a display name, precisely to avoid this kind of cross-contamination.

Color spaces have a milder version of the same problem. A document built for print might define a custom CMYK color space object; a document built for screen might use plain DeviceRGB. Merged naively without preserving each page's own resource dictionary, a page could end up interpreting its color operators against the wrong color space, shifting colors in a way that's subtle but real — a logo that was supposed to be brand-navy rendering as a slightly different blue.

Bookmarks, links, and the page-tree renumbering problem

Internal navigation is another place where a naive merge falls apart. A PDF's outline (bookmarks) and internal hyperlinks reference specific page objects directly — "jump to object 47." When pages get renumbered and reorganized into a combined tree, every one of those references has to be traced and rewritten to point at the new object IDs, or the bookmark that used to say "Section 3, page 12" now silently jumps to whatever page ended up occupying that old object slot in the merged file — which, after a merge, is usually the wrong page entirely, or worse, no page at all, causing the viewer to just fail silently on that link.

What actually gets duplicated

Because each source document keeps its own object subgraph in the output (fonts, images, color spaces and all), a merged file's size is close to the sum of its inputs' sizes, plus a small amount of overhead for the new unified cross-reference table and page tree — there's generally no deduplication of, say, a shared logo image that happens to appear in both source files, because the merge tool has no reliable way to know two visually identical images are "the same" without doing an expensive pixel comparison, and even then, subtle differences (a slightly different compression pass, different metadata) would make byte-level dedup miss it anyway. That's a reasonable tradeoff: correctness over cleverness. Merging with real deduplication is a much harder problem, and getting it wrong risks the exact glyph-substitution and color-shift bugs described above.

Why order of operations matters

One more detail that trips up people combining several files: the order you pick when queueing documents becomes the literal page order of the result, since there's no independent "sort by date" or "sort by filename" step happening under the hood — the tool just walks each source document's page tree, in the order you specified, and appends. That's why thePDF merge tool on this site lets you drag files into a specific sequence before combining them, rather than merging alphabetically or by upload time. Given how much bookkeeping happens per page during a merge — object renumbering, resource isolation, reference rewriting — getting the input order right the first time saves you from re-running the whole operation just to swap two files.