An explicit object model of PDF 1.7 / ISO 32000-1:2008, for PHP 8.3 or later.
This library represents the format's syntax and structures, down to its names, numbers, references, dictionary entries and operators. It does not aim to provide a layout API. A higher-level library can construct these objects while retaining control of their composition.
The project belongs to the PDFToolkit organization. The PDFToolkit/pdf repository is the core: it contains the objects and mechanisms described by the Adobe/ISO standard, including writing. Reading external PDFs, converting PNG/JPEG files and analyzing TrueType fonts belong to three optional packages. Each module depends on the core; installing the core to generate a PDF installs none of these modules.
The online documentation brings together guides, a reference for every component and tutorials with their code and viewable PDFs. The PDFToolkit/pdftoolkit.github.io repository retains the text, assets and build tools. This documentation presents the published core and module versions selected in the source manifest. The documentation commit is identified separately from package versions.
The 0.x series is intended for developers who want to construct and explore this model. Before 1.0, a new minor version may change names and signatures; patch releases preserve their series' API. The implemented scope and limits appear in specification coverage.
Definitions are based on the Adobe/ISO documents PDF32000_2008.pdf and adobe_supplement_iso32000.pdf, retained in the core repository. The supplement guide explains Adobe PDF 1.7 level 3 extensions, their provenance and mechanisms. The Adobe reference guide also introduces the 2006 reference, its errata, the redaction addendum and their portfolio. Adobe references archived in the core retain their original names and bytes; the four archived references are excluded from Composer archives. Core 0.6 adds the first PDF 2.0 mechanisms, with a distinct ISO 32000-2:2020 EC3 pilot catalogue. Full PDF 2.0 conformance and PDF/A, PDF/X and PDF/UA profiles remain separate work.
Installation
Core 0.6 requires PHP 8.3 or later and the ctype, iconv and zlib extensions. AES and CMS backends are optional and require openssl. The roukmoute/pdf package is available on Packagist. From the consuming project:
composer require "roukmoute/pdf:^0.6.1"
API changes appear in the changelog and the
0.5 migration guide. Keep the consuming project's
composer.lock to pin installed versions.
Optional modules
| Package | Responsibility |
|---|---|
pdftoolkit/pdf-reader |
Read objects and revisions from an external PDF, check pages and their inheritance, inspect their streams. |
pdftoolkit/pdf-images |
Inspect JPEG files and decode PNG files into core image objects. |
pdftoolkit/pdf-fonts |
Analyze a static TrueType font and prepare its metrics and mappings for core font objects. |
Since version 0.1.7, modules are compatible with core series 0.2, 0.3, 0.4, 0.5 and 0.6 and PHP 8.3 or later. All three packages are available on Packagist: reader, images and fonts. For example, to import image files with core 0.6:
composer require "roukmoute/pdf:^0.6.1" "pdftoolkit/pdf-images:^0.1.7"
The module installs the core with its stable constraint. The package guide explains boundaries, installation and reader behavior. Keep the application's composer.lock to pin the versions and commits used.
Development and checks
From a clone of the PDFToolkit/pdf repository:
export COMPOSER_ROOT_VERSION=0.6.x-dev
composer install
composer check
php examples/hello-world.php hello-world.pdf
php examples/object-stream.php object-stream.pdf
Production code depends only on PHP and these three extensions. PHPUnit 12, PHPStan, PHP-CS-Fixer and the modules used by examples and documentation are development dependencies locked in composer.lock. Their presence in this checkout adds no production dependency to applications using the core. Core CI runs tests and validates example PDFs on PHP 8.3, 8.4 and 8.5. Tests also fail on PHP deprecations and warnings. The changelog describes every published release.
To validate this checkout, including from its tag, set
COMPOSER_ROOT_VERSION=0.6.x-dev before composer install. This variable
identifies the current core as belonging to the 0.6 series expected by the
modules. Development dependencies use stable 0.1 modules, whose exact versions
and sources are locked in composer.lock. CI also defines this variable for
branches, tags and pull requests.
Construction object by object
$helvetica = new Type1Font(StandardFont::Helvetica);
$resources = new ResourceDictionary(
new Font(new DictionaryType(
new Entry(new NameType('F1'), new IndirectReference($helvetica)),
)),
);
$contents = new StreamObject(new ContentStreams(
new BeginTextObject(),
new SetTextFontAndSize(new NameType('F1'), new NumericType(18)),
new MoveTextPosition(new NumericType(72), new NumericType(720)),
new ShowText(new LiteralString('Super !')),
new EndTextObject(),
));
$page = new PageObject(
new Rectangle(new NumericType(0), new NumericType(0), new NumericType(612), new NumericType(792)),
$resources,
$contents,
);
$pages = (new PageTreeNode())->addKid($page);
$catalog = new DocumentCatalog($pages);
$file = new FileStructure(new FileHeader('1.7'), new FileBody($catalog));
$file->writeTo('hello-world.pdf');
The complete example, with imports and metadata, is in examples/hello-world.php.
Tutorials and recipes
The tutorial series accompanies each script with an explanation, a preview and variants to try. Code comments connect the objects to PDF instructions and structures.
| Topic | What the example explains |
|---|---|
| First document | Font, resources, content, page, catalog and document information. |
| Pages and text | Resource inheritance, multiple pages, positions and leading. |
| Drawing | Colors, paths, curves and graphics-state transformations. |
| Navigation | Hierarchical bookmarks and page destinations. |
| Links | Internal clickable annotations and URI actions. |
| Images | Image XObject, inline image, RGB bytes and filters. |
| Shading | PDF type 2 function and axial shading. |
| Compressed objects | Content stream, object container and cross-references. |
| TrueType font and Unicode | Embedded program, CID, widths and ToUnicode mapping. |
| JPEG and PNG images | Colors, PNG decoding, preserved JPEG and transparency mask. |
| Incremental revisions | Explicit replacements, preserved historical bytes and xref chaining. |
The table recipe assembles these concepts into a concrete presentation. The recipe collection also explains how to contribute new examples.
Identity and responsibilities
- PDF values are objects. Strings represent bytes;
TextStringexplicitly encodes Unicode text. - An
IndirectReferencetargets an instance. ASerializationContextassigns identifiers while writing a single file. There is no singleton or global counter. FileStructuredescribes the file;FileWriterwrites it. Each write creates a fresh context and derives offsets and lengths from actually emitted bytes.- Dictionaries use
Entryobjects.with()andwithout()construct copies and preserve specialized models' constraints. - Page trees and outlines use mutable graph builders with a single parent and explicit references. Their structure calculates links and counters; standard definition objects are immutable.
- Filters are applied in the reverse of their decoding order. Streams are always referenced as indirect objects.
See the architecture for construction choices and specification coverage for traceability and limits.
The component guide explains every object family. The API reference gives signatures and links to code and the standard. The site build instructions describe generation and local checks.
Coverage and limits
The catalogue inventories the reference's 392 tables, 823 indexed sections and 73 operator tokens. Dictionary tables produce named classes for dictionaries, entries and immutable definitions. PDF names retain their exact case, which is significant in the format.
Executable implementations cover fundamental objects, file writing, cross-reference tables and streams, compressed objects, content operators, page/name/number trees, destinations and outlines, standard fonts and all four PDF function representations.
A definition's presence is not a declaration of full compliance. The catalogue validates types, required references, unconditional requirements and some value forms. Conditions, relationships between dictionaries and version rules without specialized validation remain in their definitions and the coverage document.
The core composes font objects, CMaps, images and their masks, forms, tagged structure and incremental revisions. It also writes filters, explicitly selected encryption, byte-range signatures, hybrid references and linearization. Optional modules provide TrueType analysis, JPEG/PNG conversion and external-PDF reading. Verified mechanisms and remaining rules appear in the coverage inventory. Creating font program subsets, complex-script shaping and importing an external graph with remapping require dedicated components. EncodedData explicitly declares already-encoded bytes. Unsupported security obligations are rejected.
The writer currently assembles the file in memory. The reader is supplied by pdftoolkit/pdf-reader. A rendering engine and a layout API are outside the core.
Security
The security policy describes private reporting and trust boundaries. The security review explains serialization protections and application responsibilities for paths, PDF actions and resource limits.
Generating definitions
Structured resources and generated classes are versioned in the core repository. From that repository, generation is reproducible from those resources; the PDF does not need to be read again at library runtime.
python tools/generate_specification.py
The tools/extract_spec.py extractor retains the source and PDF locations. Using it requires the Python dependencies listed in the specification documentation. Normative descriptions trace constraints still to implement; class generation does not replace algorithms.