PDF syntax 101: File structure and PDF object types
Table of contents
PDF syntax describes how objects are written inside a PDF file. A conventional PDF contains a header, a body of objects, cross-reference data, and a trailer. Dictionaries connect pages, fonts, and content streams; indirect references let a reader locate and reuse objects without scanning the entire file.
Understanding PDF file structure helps when you inspect a damaged file, investigate a rendering issue, or trace a page’s resources. This guide explains the basic object types and how a reader finds them.
The PDF specification(opens in a new tab) defines the syntax. The examples below illustrate its main concepts; they aren’t a complete PDF writer or validator.
Introduction to PDF file format
A PDF stores page content and the information needed to interpret it, including fonts, images, and drawing instructions. Objects connect these resources to the document’s pages. Their order in the file doesn’t have to match the order in which pages are displayed.
PDF syntax includes readable keywords, but a PDF may also contain compressed or encrypted binary data. Opening a file in a text editor can reveal its structure without making every part readable.
File structure
The following example creates a single page containing “Hello PSPDFKit.” Save it as ASCII or UTF-8 without a byte order mark, using carriage return line feed (CRLF) line endings and a final newline after %%EOF. The offsets and stream length below are calculated for those exact bytes; preserve the spaces shown.
%PDF-1.71 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj2 0 obj<< /Type /Pages /Kids [ 3 0 R ] /Count 1 >>endobj3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [ 0 0 595 842 ] /Resources 4 0 R /Contents 5 0 R >>endobj4 0 obj<< /ProcSet[ /PDF /Text ] /Font <</Font1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >> >>endobj5 0 obj<< /Length 66 >>streamBT /Font1 35 Tf 1 0 0 1 170 450 Tm (Hello PSPDFKit) TjETendstreamendobj
xref0 60000000000 65535 f0000000010 00000 n0000000062 00000 n0000000124 00000 n0000000233 00000 n0000000353 00000 ntrailer<< /Root 1 0 R /Size 6 >>startxref475%%EOF 
The readable keywords identify objects and sections. A real PDF can also contain compressed content streams, binary images, or encrypted strings that a text editor cannot interpret directly.
Header and trailer
In the conventional table-based file structure, each part has a specific role:
| Part | Role |
|---|---|
| Header | Declares a PDF version, such as %PDF-1.7; creator metadata is stored elsewhere. |
| Body | Contains indirect objects, including page dictionaries and content streams. |
| Cross-reference table | Records object locations and generation numbers, or marks entries as free. |
| Trailer dictionary | Identifies the document catalog through /Root and records other file-level information. |
startxref and %%EOF | Locate the final cross-reference section and mark the end of the file revision. |
PDF 1.5 introduced cross-reference streams, which can replace the traditional table and carry trailer entries in their dictionary. A PDF can therefore be valid without a literal xref table. See the PDF Association’s syntax notes(opens in a new tab) for specification details and corrections.
PDF objects
PDF defines eight basic object types. The number type includes both integers and real numbers.
| PDF object type | Syntax example | Purpose |
|---|---|---|
| Boolean | true or false | Represents a logical value. |
| Number | 42 or 3.5 | Represents an integer or real value. |
| String | (Hello) or <48656C6C6F> | Stores a sequence of bytes in literal or hexadecimal notation. |
| Name | /Type | Identifies a named value or dictionary key. |
| Array | [0 0 595 842] | Holds an ordered collection of objects. |
| Dictionary | << /Type /Page >> | Maps name keys to values. |
| Stream | A dictionary followed by stream data and endstream | Stores bytes, often compressed, such as page instructions or image data. |
| Null | null | Represents the null value. |
An object’s type is separate from whether it’s direct or indirect. A direct object appears where it’s used. An indirect object has an object number and generation number and can be referenced elsewhere in the file. Streams must be indirect objects.
Direct object reference
Direct objects appear inline where they’re used.
This resource dictionary contains a direct font dictionary for Helvetica, one of PDF’s standard Type 1 fonts. It illustrates nesting and is a fragment, not a complete PDF file:
<< /ProcSet[ /PDF /Text ] /Font <</Font1<</BaseFont/Helvetica/Subtype/Type1/Type/Font>> >> >>Indirect object reference
An indirect object is defined between obj and endobj, with a positive object number and a generation number. The generation number is commonly zero; it can change when a freed object number is reused.
A reference such as 3 0 R means “object number three, generation zero.” Object numbers identify objects within the file; they don’t specify page order.
This abbreviated example shows one dictionary defined as an indirect object and another dictionary referring to it:
3 0 obj<</BaseFont/Helvetica/Subtype/Type1/Type/Font>>endobj
4 0 obj<< /ProcSet[ /PDF /Text ] /Font <</Font1 3 0 R >> >>endobjDocument catalog and page tree
The trailer’s /Root entry points to the document catalog, a dictionary with /Type /Catalog. The catalog’s /Pages entry points to the root of the page tree.
A page-tree node uses /Kids to list child page nodes or other page-tree nodes. A leaf page dictionary has /Type /Page. Its /Contents entry refers to the page’s drawing instructions, and its resources identify items such as fonts and images.
In the opening example, the catalog refers to object two, which refers to the page in object three. The page then refers to its resources and content stream. A reader follows these references to assemble the page.
Cross-reference
A reader locates indirect objects through cross-reference data. In a conventional PDF, it looks near the end for the final startxref entry and follows the byte offset to the cross-reference table or stream.
That lookup doesn’t mean a viewer reads every byte backward. It uses the index to request the objects it needs. Linearized PDFs additionally arrange data to support displaying the first page while the rest of a document is being transferred.
In the opening example, with the specified CRLF line endings, the xref keyword begins at byte offset 475:
startxref475The matching cross-reference subsection is shown below. Each entry is 20 bytes long, including its CRLF line ending:
xref0 60000000000 65535 f0000000010 00000 n0000000062 00000 n0000000124 00000 n0000000233 00000 n0000000353 00000 nThe 0 6 line declares a subsection starting at object zero with six entries. For an in-use entry ending in n, the first field is the object’s byte offset, and the second is its generation number. An entry ending in f is free; its first field participates in a list of free entries rather than pointing to an object body.
Object zero is reserved and marked free with generation number 65535. It isn’t an empty page or a content object.
Cross-reference streams and incremental updates
Cross-reference streams encode the index as stream data. They can identify objects stored inside compressed object streams, so not every entry is a direct byte offset to an object body.
An incremental update appends changed objects and new cross-reference data to the existing file. The latest trailer can point to the preceding cross-reference section through /Prev. A reader follows that chain to resolve the current objects. The PDF Association glossary(opens in a new tab) explains the related terms.
Why copied PDF examples may not open
The opening example uses CRLF line endings so its cross-reference entries have the required width. Saving it with LF line endings, adding a byte order mark, or changing whitespace changes byte positions. If you alter the example, recalculate its offsets and stream length. Font definitions and trailer entries also need to satisfy the specification.
Use a PDF library to write the file and a validator to check its structure. A viewer may repair a damaged file while opening it, so successful rendering alone doesn’t prove validity. See how to check whether a PDF is valid.
Learn more
The object model explains how pages refer to fonts, images, and content streams. Cross-reference data lets a reader find those objects without treating the PDF as a sequential text document.
For the rendering step, read our guide to the complexities of PDF rendering. The PDF Association’s minimal-file examples(opens in a new tab) provide a useful next step for studying valid serialized files.
FAQ
A conventional PDF contains a header, indirect objects, cross-reference data, and a trailer. The document catalog and page tree connect the objects needed to display each page. Newer files may use cross-reference streams instead of a traditional table.
The eight basic PDF object types are Boolean, number, string, name, array, dictionary, stream, and null. Numbers can be integers or real values. These types describe object values; direct and indirect describe how objects are stored and referenced.
An indirect object has an object number and a generation number. Other objects refer to it using those numbers followed by R. Cross-reference data tells the reader where to find it.
startxref mean in a PDF?The number after startxref is a byte offset from the beginning of the file to its cross-reference table or stream. Readers use the final entry to locate the latest cross-reference data.
A reader may begin near the end to find cross-reference information, but it doesn’t read the whole document backward. It follows references to the objects needed for the requested pages.
xref table?Yes. PDF 1.5 and later can use a cross-reference stream instead of a text-based xref table. Searching for the literal keyword alone isn’t a validity check.