PDF Cross-Reference Stream

A PDF cross-reference stream is a compressed alternative to the traditional cross-reference table, introduced in PDF 1.5. It stores byte offsets for all indirect objects in a Flate-compressed stream rather than a fixed-width ASCII table. Cross-reference streams also embed the trailer dictionary directly, reducing file size and enabling object stream compression.

A PDF cross-reference stream is a compressed alternative to the traditional <a href="https://pdftheguide.com/glossary/pdf-cross-reference-table" target="_blank" rel="noopener">cross-reference table</a> (xref table), introduced in <a href="https://www.iso.org/standard/51502.html" target="_blank" rel="noopener">PDF 1.5</a>. While a cross-reference table stores byte offsets in plain ASCII text within a rigid positional format, a cross-reference stream stores the same offset information as a compressed binary stream object — typically using <a href="https://pdftheguide.com/glossary/pdf-compression" target="_blank" rel="noopener">Flate (zlib/DEFLATE) compression</a>. Cross-reference streams were standardised as part of <a href="https://www.iso.org/standard/63534.html" target="_blank" rel="noopener">ISO 32000-2:2017 (PDF 2.0)</a> and are the preferred format in modern PDF files.

Cross-reference streams serve two purposes: they reduce file size (especially in documents with many objects), and they enable <a href="https://pdftheguide.com/glossary/pdf-object-stream" target="_blank" rel="noopener">object streams</a> — another PDF 1.5 feature that stores multiple PDF objects compressed together. Object stream entries are not individually byte-addressable, so their positions are tracked using a generation/index number within the object stream rather than an absolute byte offset, a mechanism that the cross-reference stream's entry type field was designed to support.

Structure of a cross-reference stream

A cross-reference stream is a regular PDF stream object whose stream dictionary includes cross-reference-specific entries in addition to the standard stream dictionary entries:

<strong>/Type /XRef</strong> — Marks the object as a cross-reference stream. Required.

<strong>/Size</strong> — The total number of objects in the PDF (same semantics as in the traditional xref table trailer dictionary). Required.

<strong>/W</strong> — A three-element array specifying the byte widths of each field in each cross-reference entry. The three fields are: type (0, 1, or 2), field 2 (meaning depends on type), and field 3 (meaning depends on type). Example: <code>/W [1 3 1]</code> means the type field is 1 byte, field 2 is 3 bytes, and field 3 is 1 byte.

<strong>/Index</strong> — An array specifying which object numbers the entries in this stream cover, in the format <code>[first_obj_num count first_obj_num count ...]</code>. Optional; if absent, the stream covers objects 0 to /Size-1.

<strong>/Prev</strong> — The byte offset of the previous cross-reference stream in the file (for incremental updates). Same role as /Prev in the traditional xref trailer.

The cross-reference stream also incorporates the trailer dictionary entries directly (eliminating the need for a separate <code>trailer</code> keyword block): /Root (the document catalogue), /Info (document information dictionary), /Encrypt, and /ID.

Entry types in the stream data

Each entry in a cross-reference stream describes one object. The entry type (field 1) determines how the remaining fields are interpreted:

<strong>Type 0 — Free objects</strong>: The object is free (deleted or not yet used). Field 2 is the object number of the next free object in the free list. Field 3 is the generation number to be used when the object is next allocated. This is the compressed equivalent of the <code>f</code> (free) entry type in a traditional xref table.

<strong>Type 1 — In-use objects (uncompressed)</strong>: The object is an uncompressed, directly accessible object. Field 2 is the byte offset of the object from the beginning of the file. Field 3 is the object's generation number. This is the compressed equivalent of the <code>n</code> (in-use) entry type in a traditional xref table.

<strong>Type 2 — In-use objects (compressed, in an object stream)</strong>: The object is compressed within an <a href="https://pdftheguide.com/glossary/pdf-object-stream" target="_blank" rel="noopener">object stream</a>. Field 2 is the object number of the containing object stream. Field 3 is the index of this object within the object stream (zero-based). There is no generation number for type 2 entries — compressed objects always have generation 0.

The binary encoding means that reading a cross-reference stream requires decompressing the stream, then parsing fixed-width binary records according to the /W field widths. PDF parsers that only support traditional xref tables cannot read cross-reference stream files correctly.

Relationship to object streams and PDF 1.5 compression

Cross-reference streams and object streams were introduced together in PDF 1.5 as a package of compression improvements. They work together:

<strong>Object streams</strong> (<code>/Type /ObjStm</code>) group multiple indirect objects together into a single compressed stream. Each compressed object within the stream is assigned a sequential index (0, 1, 2, ...). The objects themselves have normal object numbers, but instead of residing at byte offsets in the file, they exist only within the object stream.

<strong>Cross-reference streams track object stream members</strong> using Type 2 entries. When a PDF viewer needs to read object 42 (which is compressed in object stream 100, at index 3), the xref stream entry for object 42 is: type=2, field2=100 (object stream number), field3=3 (index within stream). The viewer reads object stream 100, decompresses it, and locates the third object within it.

<strong>File size reduction</strong>: The combination of cross-reference streams and object streams typically reduces PDF file size by 10–30% for text-heavy documents. The reduction is more significant for files with many small objects (typical in documents with extensive metadata, bookmarks, or complex structure trees).

<strong>Linearisation interaction</strong>: Linearised PDFs (optimised for fast web display) can use cross-reference streams. The linearisation dictionary and hints tables interact with cross-reference streams in a specific way defined in the PDF specification.

<strong>Compatibility</strong>: PDF viewers that do not support PDF 1.5+ (increasingly rare, but still encountered in some legacy embedded systems) cannot read cross-reference streams. For maximum compatibility, some PDF creation tools offer a "save as PDF 1.4" option that expands object streams and writes traditional xref tables.

Frequently asked questions

What is the difference between a cross-reference table and a cross-reference stream?

A cross-reference table (xref table) is the traditional PDF mechanism for locating objects: it stores byte offsets in plain ASCII text in a fixed-format table near the end of the file. A cross-reference stream is a compressed binary alternative introduced in PDF 1.5: it stores the same byte offset information in a Flate-compressed stream object. The stream format is smaller (due to compression), eliminates the need for a separate trailer dictionary block, and supports the Type 2 entry type for objects stored in object streams. Both serve the same purpose — enabling the PDF viewer to quickly locate any object in the file without reading the entire file — but cross-reference streams are the modern preferred format for PDF 1.5+ files.

Can a PDF have both a cross-reference table and a cross-reference stream?

A PDF file cannot mix both in the same revision, but an updated PDF (one that has had incremental updates appended) can have different revision types: the original revision might use a traditional xref table, and a subsequent incremental update appended to it might use a cross-reference stream. The /Prev entry chains the cross-reference structures together. PDF parsers must be able to follow this chain regardless of whether each revision uses a table or a stream. In practice, most modern PDF creation tools consistently use one type throughout; cross-reference stream files typically use streams for all revisions including incremental updates.

Do all PDF viewers support cross-reference streams?

All current major PDF viewers — Adobe Acrobat Reader, Chrome's built-in PDF viewer, Firefox (PDF.js), Apple Preview on macOS/iOS, Foxit Reader, and PDF.js-based viewers — support cross-reference streams, since they require PDF 1.5+ support. Legacy or embedded PDF viewers in older devices (some older e-readers, document management systems, or embedded systems) may only support PDF 1.4 and will fail to parse cross-reference streams. For documents targeting maximum compatibility with very old viewers, generating PDF 1.4 output (which uses only traditional xref tables and no object streams) remains the safe option.