How PDF Merging Works in Web Browsers
Merging PDF documents without sending files to an external server requires parsing binary object streams, remapping object identifiers (IDs), and restructuring the root catalog directly in JavaScript memory.
1. The Internal Structure of a PDF File
A Portable Document Format (PDF) file is not a flat image or text stream. Instead, it is an indexed object-graph defined by the ISO 32000 standard. Every PDF consists of four distinct structural zones: the Header (identifying PDF version), the Body (a collection of indirect objects such as fonts, text streams, and images), the Cross-Reference (XRef) Table (byte-offset positions of each object), and the Trailer (pointers to the catalog dictionary and start of the XRef table).
When two PDF documents are merged, simply appending byte arrays together corrupts the file. Both files contain duplicate object numbers (e.g. Object 1:0 and Object 2:0 exist in both source files) and their byte offsets no longer match.
| PDF Component | Role in Single Document | Role During Browser Merge |
|---|---|---|
| Header | Defines PDF spec (e.g. %PDF-1.7) | Adopt highest spec of input documents |
| Body Objects | Stores vector paths, fonts, pages | Renumbered to prevent collision (ID offsets) |
| XRef Table | Byte offsets for fast random access | Completely regenerated for output buffer |
| Trailer / Catalog | Root node of the page tree | Merged into single parent /Pages node |
2. The Client-Side Concatenation Algorithm
Modern in-browser PDF utilities load the source PDF byte arrays into an ArrayBuffer using JavaScript typed arrays (Uint8Array). The parser traverses the document tree to locate the root Pages dictionary.
For each page imported from Document B, the engine shifts its indirect object references by the highest object ID present in Document A. Once all page dictionaries are linked under a unified /Pages tree with an updated /Count attribute, the engine computes exact byte offsets for every object and writes a fresh XRef table before closing with a new %%EOF marker.
3. Why In-Browser Merging Protects Privacy
Because the entire parsing, object re-numbering, and serialization process executes in the local browser runtime memory via WebAssembly or optimized JavaScript, no document bytes need to travel over an internet connection to a remote conversion farm.
