Anatomy of a real, minimal PDF
This is a complete PDF 1.4 file, 591 bytes, which passes qpdf --check. Pick a part of the file to see what it does. The xref offsets are exact.
How a reader opens a file
Readers parse PDFs backwards, starting at the end:
startxref; the number after it is the byte offset of the last cross-reference section./Prev, follow it to the previous xref section (incremental updates) and merge, newest entries winning./Root is the document catalog. From there: /Pages → page tree → leaf /Page objects./Resources, decode /Contents, and run the operators.Incremental updates
Edits can be appended instead of rewriting the file: new or changed objects, a new xref section listing only them, and a new trailer whose /Prev points to the old xref. The original bytes are untouched, which is what lets a document carry several digital signatures, each covering the file as it was when signed.
…original file… %%EOF 3 0 obj % changed page << … /Annots [6 0 R] >> endobj 6 0 obj % new annotation << /Type /Annot /Subtype /Text … >> endobj xref 0 1 0000000000 65535 f 3 1 0000000431 00000 n 6 1 0000000560 00000 n trailer << /Size 7 /Root 1 0 R /Prev 338 >> startxref 640 %%EOF
Offsets in this update snippet are illustrative. Worked example: 1.4 App. G.6, 1.7 Annex H.7
Linearization ("Fast Web View")
A linearized file reorders objects so that the first page, and a hint table, come first. A viewer can show page 1 while the rest downloads and fetch other pages with HTTP range requests. You can spot one by a /Linearized dictionary in the first object. It is fiddly to write correctly, and an incremental update breaks it. (1.4 App. F, 1.7 Annex F)