PHPackages                             papier/papier - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. papier/papier

ActiveLibrary[PDF &amp; Document Generation](/categories/documents)

papier/papier
=============

A comprehensive PHP library for generating and reading PDF documents, implementing ISO 32000-1:2008 (PDF 1.7)

v3.0.0(1mo ago)2216MITPHPPHP &gt;=8.1CI passing

Since Dec 28Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/mikaelcarlavan/papier)[ Packagist](https://packagist.org/packages/papier/papier)[ Docs](https://papier.io)[ Fund](https://www.buymeacoffee.com/mikaelcarlavan)[ RSS](/packages/papier-papier/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (10)Dependencies (6)Versions (15)Used By (0)

Papier
======

[](#papier)

 [![CI](https://github.com/mikaelcarlavan/papier/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/mikaelcarlavan/papier/actions/workflows/ci.yml) [![Documentation](https://github.com/mikaelcarlavan/papier/actions/workflows/docs.yml/badge.svg?branch=master)](https://github.com/mikaelcarlavan/papier/actions/workflows/docs.yml) [![Latest Stable Version](https://camo.githubusercontent.com/ee145222904b93a7743d281a2c2b99179cb071686ffb244d81bb134d403f5395/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7061706965722f706170696572)](https://packagist.org/packages/papier/papier) [![Total Downloads](https://camo.githubusercontent.com/7e7cfd799394d539d1e4aa14bab3b26ea7fc6dfed0273bf32805f6a3108ade6a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7061706965722f706170696572)](https://packagist.org/packages/papier/papier) [![PHP Version](https://camo.githubusercontent.com/799663e38752e8f3683f2dd3ee1a63a7d0f22203555544f89ec596e60dc162ae/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f7061706965722f706170696572)](https://img.shields.io/packagist/php-v/papier/papier) [![License](https://camo.githubusercontent.com/9f0a2f50b5beadadc6d12c5ce9692bcdfc1118dee85478140ebb6b70d363f709/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7061706965722f706170696572)](https://packagist.org/packages/papier/papier)

A comprehensive PHP library for generating and reading PDF documents, implementing **ISO 32000-1:2008 (PDF 1.7)** with selected **ISO 32000-2 (PDF 2.0)** features (AES-256, document timestamps).

Papier was built with the assistance of [Claude](https://claude.ai) (Anthropic's AI assistant), which helped design the API, implement the PDF specification, and write the examples throughout the library.

Features
--------

[](#features)

**Documents &amp; pages**

- Create documents with metadata (Info dictionary + XMP), viewer preferences, page labels, named destinations, open actions
- Page sizes/orientation, rotation, multiple content streams
- Page operations: merge, extract/split, N-up, import pages from other PDFs
- Repeating elements — running headers/footers with page-rule filtering (`all`/`odd`/`even`/`first`/`last`/every-Nth/callable) and "Page X of Y"

**Text &amp; fonts**

- 14 standard Type 1 fonts; embedded TrueType/OpenType (`FontFile2`)
- **TrueType subsetting** + automatic **`/ToUnicode`** generation (searchable, copy-pasteable)
- **Type 0 / CIDFontType2 composite fonts** (Identity-H) for full Unicode / CJK
- **Type 3** user-defined glyph fonts; WinAnsi &amp; MacRoman encodings
- Text rendering modes, char/word spacing, horizontal scaling, rise, leading; `TextBox` word-wrap

**Graphics**

- Paths, shapes, Bézier curves, clipping; line styles, dashes
- Colour spaces: DeviceGray/RGB/CMYK, CalGray/CalRGB, Lab, ICCBased, Indexed, Separation, DeviceN, Pattern
- Functions (sampled, exponential, stitching, PostScript calculator)
- Shadings: axial, radial, and **mesh types 4–7** (Gouraud free-form/lattice, Coons, tensor)
- Patterns: tiling and **shading patterns** (fill shapes/text with gradients)
- Transparency: ExtGState, soft masks, blend modes
- Images: JPEG, PNG (with alpha → SMask), image masks, decode arrays

**Tables, forms &amp; annotations**

- Tables: column widths, header/footer rows, rowspan, per-side borders, padding, vertical alignment, colours, opacity
- AcroForm fields (text, checkbox, radio, combo, list, push button, signature); **fill existing forms** with regenerated appearance streams
- 14 annotation subtypes incl. link, text, markup, geometric, stamp, ink, **redaction**

**Document features**

- Bookmarks/outlines, optional content (layers), multimedia (sound/screen renditions), page transitions
- File attachments; **Tagged PDF** (marked content, structure tree, `/ParentTree`) for accessibility / PDF/UA
- **PDF/A** (2b and accessible 2a) with sRGB OutputIntent + a built-in `PdfAValidator`

**Security &amp; signatures**

- Encryption: RC4 (40/128-bit), AES-128, **AES-256** (PDF 2.0); permission flags
- **Decryption** of existing encrypted PDFs (RC4/AES-128/AES-256), user &amp; owner passwords
- **Digital signatures** (PKCS#7/CMS detached) with visible appearance; **RFC 3161 document timestamps** (PAdES)

**File structure**

- Classic xref tables **and** cross-reference streams; **object streams** (read &amp; write) for smaller files
- **Incremental updates** (append revisions; foundation for signing)
- Damaged-file recovery (rebuild xref by scanning when `startxref` is missing/corrupt)
- Filters: FlateDecode (+predictors), LZW, ASCIIHex, ASCII85, RunLength, **CCITT Group 4**; DCT/JBIG2/JPX pass-through

**Reading &amp; extraction**

- Layout- and `ToUnicode`-aware text extraction (Type 0/CJK/subset fonts, recurses into form XObjects)
- Read pages, fonts, images, metadata (Info + XMP), annotations, outlines, form-field values, attachments, structure tree
- Parses object streams, hybrid-reference and linearized files; robust against malformed input

Documentation
-------------

[](#documentation)

****

Installation, a quick start, and a chapter for each subsystem — documents and pages, text and fonts, graphics, images, tables, forms, annotations, navigation, layers and multimedia, encryption and signatures, tagged PDF and PDF/A, file structure, and reading.

[Installation](https://mikaelcarlavan.github.io/papier/installation.html)Composer setup and extension checks[Quick start](https://mikaelcarlavan.github.io/papier/quickstart.html)Build a complete document in a few minutes[Examples](https://mikaelcarlavan.github.io/papier/examples.html)All 34 runnable scripts, by themeThe site is served from [`docs/`](docs/) and generated from the fragments in `docs/_content/` by `php tools/build-docs.php`. To preview it locally:

```
php -S 127.0.0.1:8000 -t docs
```

See [`docs/README.md`](docs/README.md) for the editing workflow.

Requirements
------------

[](#requirements)

- PHP 8.1+
- Extensions: `ext-zlib`, `ext-mbstring`, `ext-openssl`

Installation
------------

[](#installation)

```
composer require papier/papier
```

What you can do
---------------

[](#what-you-can-do)

### Create documents

[](#create-documents)

```
use Papier\PdfDocument;

$doc = PdfDocument::create();
$doc->setTitle('My Document')
    ->setAuthor('Jane Doe')
    ->setSubject('A sample PDF');

$page = $doc->addPage();          // A4 by default
$doc->save('output.pdf');
```

### Text and typography

[](#text-and-typography)

Add text with fonts, sizes, colours, and opacity. Latin characters (é, à, ü, ñ, …) work out of the box.

```
use Papier\Elements\{Color, Text, TextBox};

$font = $doc->addFont('Helvetica');
$bold = $doc->addFont('Helvetica-Bold');

$page->add(
    Text::write('Bonjour, Ré!')->at(72, 750)->font($bold, 24)->color(Color::hex('#1a1a2e')),
    TextBox::write('Un paragraphe avec retour à la ligne automatique.')
        ->at(72, 700)->size(450, 80)
        ->font($font, 12)
        ->lineHeight(1.5),
);
```

### Embedded TrueType / OpenType fonts

[](#embedded-truetype--opentype-fonts)

```
$lato = $doc->addFont(__DIR__ . '/Lato-Regular.ttf');

$page->add(
    Text::write('Lato at 18 pt')->at(72, 680)->font($lato, 18),
);
```

Papier extracts the PostScript name from the font's `name` table, parses metrics from `hhea` / `OS/2` / `hmtx`, and embeds the full font program as `FontFile2`.

### Images

[](#images)

Load JPEG or PNG images from a file path — type is auto-detected:

```
use Papier\Elements\Image;

$page->add(
    Image::fromFile(__DIR__ . '/photo.png')->at(72, 500)->fitWidth(300),
);
```

Or from raw bytes if you already have them in memory:

```
$page->add(
    Image::fromJpeg(file_get_contents('photo.jpg'))->at(72, 400)->size(200, 150)->opacity(0.8),
    Image::fromPng(file_get_contents('logo.png'))->at(300, 400)->fitHeight(60),
);
```

PNG alpha channels are handled automatically via an SMask XObject.

### Graphics

[](#graphics)

Rectangles, circles, lines, curves, complex paths, gradients, patterns, and clipping:

```
use Papier\Elements\{Circle, Line, Rectangle};

$page->add(
    Rectangle::create(72, 400, 200, 100)->fill(Color::rgb(0.2, 0.5, 0.9))->stroke(Color::black(), 1.5),
    Circle::create(400, 450, 50)->fill(Color::hex('#e74c3c')),
    Line::from(72, 380)->to(523, 380)->color(Color::gray(0.5))->width(0.5),
);
```

For lower-level control use `ContentStream` directly (PDF operators: `re`, `m`, `l`, `c`, `Tf`, `Tj`, …).

### Tables

[](#tables)

```
use Papier\Elements\{Color, Table};

$table = Table::create(72, 700)                  // top-left anchor
    ->setColumnWidths(100, 150, 180)
    ->setFont($font, 10, 'Helvetica')            // 3rd arg = metrics for wrapping
    ->setHeaderFont($bold, 10, 'Helvetica-Bold')
    ->setHeaderRows(1)
    ->setHeaderBg(Color::rgb(0.12, 0.22, 0.42))
    ->setHeaderTextColor(Color::white());

$table->addRow(['Name', 'Role', 'Email']);
$table->addRow(['Alice', 'Engineer', 'alice@example.com']);
$table->addRow(['Bob',   'Designer', 'bob@example.com']);

$page->add($table);
```

Pass a `TableCell` instead of a string to override the table defaults for one cell. Features: column widths, header/footer rows, row/cell colours, padding, border control per side, `colspan`/`rowspan`, vertical alignment, opacity.

### Interactive forms (AcroForm)

[](#interactive-forms-acroform)

```
use Papier\AcroForm\{AcroForm, TextField, CheckBoxField, ComboBoxField};

$form = new AcroForm();

$name = new TextField('person.name');
$name->setRect(200, 700, 400, 718)
     ->setDefaultAppearance($font, 12)
     ->setValue('Alice');
$form->addField($name);

$doc->setAcroForm($form);
```

Supported field types: `TextField`, `CheckBoxField`, `RadioButtonField`, `ComboBoxField`, `ListBoxField`, `PushButtonField`, `SignatureField`.

### Annotations

[](#annotations)

```
use Papier\Annotation\{HighlightAnnotation, LinkAnnotation, StampAnnotation};
use Papier\Elements\Color;

$link = new LinkAnnotation(72, 680, 272, 700);
$link->setURI('https://example.com')->setBorderStyle(0);
$page->addAnnotation($link);

$stamp = new StampAnnotation(390, 555, 520, 605);
$stamp->setIcon('Draft')->setColor(Color::rgb(1, 0, 0));
$page->addAnnotation($stamp);
```

14 page-markup subtypes: `TextAnnotation`, `LinkAnnotation`, `FreeTextAnnotation`, `HighlightAnnotation`, `UnderlineAnnotation`, `StrikeOutAnnotation`, `SquigglyAnnotation`, `LineAnnotation`, `SquareAnnotation`, `CircleAnnotation`, `PolygonAnnotation`, `StampAnnotation`, `InkAnnotation`, `RedactAnnotation`.

`src/Annotation/` also holds the subtypes driven by other subsystems — `WidgetAnnotation` (form fields), `ScreenAnnotation`, `SoundAnnotation` and `MovieAnnotation` (multimedia), `PopupAnnotation`, `FileAttachmentAnnotation`, `CaretAnnotation`, `PolyLineAnnotation`, `WatermarkAnnotation`, `PrinterMarkAnnotation`, `TrapNetAnnotation` and `ThreeDAnnotation`.

Rectangles are constructor arguments; `setRect()` is not part of the public API.

### Bookmarks (outlines)

[](#bookmarks-outlines)

```
use Papier\Structure\{PdfOutline, PdfOutlineItem};
use Papier\Destination\XYZDestination;

$outline = new PdfOutline();

$ch1 = new PdfOutlineItem('Chapter 1');
$ch1->setBold(true)
    ->setDestination(XYZDestination::create($page1->getDictionary(), 0, 841));

$sec = new PdfOutlineItem('Section 1.1');
$sec->setDestination(XYZDestination::create($page2->getDictionary(), 0, 841));

$ch1->addChild($sec);
$outline->addItem($ch1);

$doc->setOutline($outline);
```

Items also take `setColor()`, `setItalic()`, and `setAction()` for a non-destination target such as a URI.

### Document-level features

[](#document-level-features)

```
// Named destinations and open action
$doc->addNamedDestination('intro', $page, 72, 750);
$doc->setOpenDestination($page, 0, 841);

// Page labels (Roman numerals, letters, custom prefix…)
use Papier\Structure\PageLabelStyle;
$doc->addPageLabel(0, PageLabelStyle::RomanLower);              // i, ii, iii, …
$doc->addPageLabel(4, PageLabelStyle::Decimal);                 // 1, 2, 3, …
$doc->addPageLabel(4, PageLabelStyle::Decimal, prefix: 'p.');   // p.1, p.2, …

// File attachments
$doc->attachFile('data.json', file_get_contents('data.json'), 'application/json');

// Password protection and permissions (see "Encrypt a document" below)
$doc->encrypt(userPassword: 'user', ownerPassword: 'owner');
```

### Optional content (layers)

[](#optional-content-layers)

```
use Papier\OptionalContent\{OCGroup, OCProperties};

$bg   = new OCGroup('Background');
$text = new OCGroup('Text');

$ocProps = new OCProperties();
$ocProps->addOCG($bg)->addOCG($text)
        ->setDefaultConfig('Default', on: [$bg, $text]);
$doc->setOCProperties($ocProps);
```

Wrap content in `ContentStream::beginMarkedContentProps('OC', …) / endMarkedContent()` to bind it to a layer.

### Multimedia

[](#multimedia)

```
use Papier\Multimedia\{MediaClip, MediaPlayParams, MediaRendition};
use Papier\Annotation\ScreenAnnotation;

$params = (new MediaPlayParams())->setVolume(80)->setAutoPlay(true)->setShowControls(true);

$clip      = MediaClip::fromFile('demo.mp4', 'video/mp4', 'Demo');
$rendition = new MediaRendition($clip, 'Demo');
$rendition->setPlayParams($params);

$screen = new ScreenAnnotation(72, 400, 372, 600);
$screen->setRendition($rendition->getDictionary());
$page->addAnnotation($screen);
```

`MediaClip::fromEmbedded()` embeds the media in the PDF instead of referencing an external file.

### Page transitions

[](#page-transitions)

```
use Papier\Structure\PageTransition;

$page->setTransition(new PageTransition(PageTransition::DISSOLVE, 1.0));

// Style and duration are constructor arguments; direction, dimension and motion
// are set afterwards:
$page2->setTransition(
    (new PageTransition(PageTransition::WIPE, 0.6))->setDirection(0)   // left → right
);
```

Styles: `REPLACE`, `SPLIT`, `BLINDS`, `BOX`, `WIPE`, `DISSOLVE`, `GLITTER`, `FLY`, `PUSH`, `COVER`, `UNCOVER`, `FADE`.

### Page operations &amp; repeating elements

[](#page-operations--repeating-elements)

```
use Papier\PageRule;

// Running header/footer on every page (rendered when the total is known):
$doc->footer(fn($page, $n, $total) =>
    $page->add(Text::write("Page $n of $total")->at(480, 30)->font($font, 9)));
// PageRule::All|Odd|Even|First|Last, an int N (every Nth page), or a callable:
$doc->header(fn($page, $n, $total) =>
    $page->add(Text::write('Draft')->at(72, 810)->font($font, 9)), PageRule::Odd);

// Document-level page operations:
PdfDocument::merge(['a.pdf', 'b.pdf'], 'out.pdf');        // concatenate
PdfDocument::extractPages('in.pdf', [3, 1], 'out.pdf');  // subset, reordered
PdfDocument::nUp('in.pdf', 2, 2, 'out.pdf');             // 4-up
$doc->importPages('in.pdf');                              // import all pages
$page->setRotation(90);                                   // rotate
```

### Validate your own output (PDF/A)

[](#validate-your-own-output-pdfa)

```
use Papier\Validation\PdfAValidator;

$issues = PdfAValidator::validate($pdfBytes);   // [] = structurally conformant
```

Plus `php tools/verify.php` renders every example with Ghostscript and runs `qpdf --check` to confirm the files actually display.

### Fill an existing form

[](#fill-an-existing-form)

```
use Papier\AcroForm\FormFiller;

$filler = new FormFiller(file_get_contents('form.pdf'));

$filler->getFieldNames();                   // discover what the form contains
$filler->setText('person.name', 'Alice')
       ->setCheckbox('subscribe', true);

$filler->saveAs('filled.pdf');              // appearance regenerated, incremental
$bytes = $filler->save();                   // or get the bytes back
```

### Visible signatures + timestamps (PAdES)

[](#visible-signatures--timestamps-pades)

```
use Papier\Signature\{PdfSigner, DocumentTimestamp};

$signed = (new PdfSigner($certPem, $keyPem))
    ->setName('Alice')->setReason('Approved')
    ->setVisibleAppearance(x: 360, y: 690, w: 170, h: 60, page: 1)
    ->sign(file_get_contents('in.pdf'));

// Optional RFC 3161 document timestamp (supply your TSA transport).
$timestamped = (new DocumentTimestamp($tsaClient))->apply($signed);
```

### CCITT Group 4 (fax) images

[](#ccitt-group-4-fax-images)

```
use Papier\Filter\CCITTFaxDecode;

$codec   = new CCITTFaxDecode();
$encoded = $codec->encode($bilevelBytes, $params);   // K=-1; ~10× on scans
$decoded = $codec->decode($encoded, $params);        // also reads scanned PDFs
```

### Tagged PDF / accessibility

[](#tagged-pdf--accessibility)

```
use Papier\LogicalStructure\{StructElement, StructTreeRoot};

$cs->beginMarkedContentMcid('P', 0)->beginText()/* … */->endText()->endMarkedContent();

$tree = new StructTreeRoot();
$p = new StructElement('P');
$p->addMCID(0, $page->getDictionary());
$tree->addChild($p);
$doc->setStructTree($tree);   // emits /MarkInfo, /ParentTree, /StructParents
```

Enables screen-reader support and the accessible **PDF/A-2a / PDF/UA** levels.

### Shading patterns — fill shapes &amp; text with gradients

[](#shading-patterns--fill-shapes--text-with-gradients)

```
use Papier\Graphics\Pattern\ShadingPattern;

$pat = new ShadingPattern($axialShading);            // or a radial/mesh shading
$page->getResources()->addPattern('G', $pat->getDictionary());
$cs->setFillColorSpace('Pattern')->setFillColorN('G')->drawRect(...)->fill();
```

### Type 3 (user-defined glyph) fonts

[](#type-3-user-defined-glyph-fonts)

```
use Papier\Font\Type3Font;

$f = new Type3Font();
$f->setFontBBox(0, 0, 1000, 1000);
$glyph = (new ContentStream())->drawCircle(500, 350, 350)->fill();
$f->addGlyph(65, $glyph, 1000, 'disc');              // 'A' → a disc
$name = $doc->registerFont($f, 'Icons');
```

### Recover damaged PDFs

[](#recover-damaged-pdfs)

The parser rebuilds the cross-reference by scanning for objects when `startxref` is missing or corrupt — common with third-party files.

```
$parser = new PdfParser($maybeBrokenBytes);
$parser->parse();        // recovers automatically; no special flag needed
```

### Full-Unicode / CJK text (Type 0 fonts)

[](#full-unicode--cjk-text-type-0-fonts)

`addFont()` produces a single-byte WinAnsi font (256 codes). For CJK, Cyrillic, Greek, and other scripts, use `addUnicodeFont()` — it embeds the font as a CIDFontType2 with Identity-H encoding, generates a `/ToUnicode` CMap, and subsets unused glyphs.

```
$noto = $doc->addUnicodeFont(__DIR__ . '/NotoSansCJK-Regular.otf');
$page->add(Text::write('日本語 / 中文 / 한국어 / Ελληνικά')->at(72, 700)->font($noto, 16));
```

### Mesh shadings (types 4–7)

[](#mesh-shadings-types-47)

```
use Papier\Graphics\Shading\{GouraudTriangleShading, CoonsPatchShading};

$tri = new GouraudTriangleShading('DeviceRGB');
$tri->addTriangle([72, 600], [1,0,0], [222, 600], [0,1,0], [147, 740], [0,0,1]);
$page->getResources()->addShading('M4', $tri->toStream());   // paint with `sh`
```

Supports free-form (4) and lattice (5) Gouraud triangle meshes, Coons (6) and tensor-product (7) patch meshes.

### Digital signatures

[](#digital-signatures)

```
use Papier\Signature\PdfSigner;

$signer = new PdfSigner($certPem, $keyPem);   // PEM strings or file paths
$signer->setReason('Approved')->setLocation('Paris');
file_put_contents('signed.pdf', $signer->sign(file_get_contents('in.pdf')));
```

Adds an invisible PKCS#7 (CMS) detached signature as an incremental update, so the original bytes and any prior signatures remain valid.

### Encrypt a document

[](#encrypt-a-document)

```
use Papier\Encryption\{EncryptionAlgorithm, StandardSecurityHandler};

$doc->encrypt(
    userPassword:  'user',                        // required to open (empty = none)
    ownerPassword: 'owner',                       // bypasses restrictions
    permissions:   StandardSecurityHandler::PERM_PRINT | StandardSecurityHandler::PERM_COPY,
    algorithm:     EncryptionAlgorithm::Aes_256,   // ::Aes_128 (default), ::Rc4_128, ::Rc4_40
);
```

Permissions are `PERM_*` flags OR-ed together (`PERM_ALL` by default).

### Viewer preferences

[](#viewer-preferences)

```
use Papier\Viewer\{ViewerPreferences, PrintScaling, Duplex, NonFullScreenPageMode, ReadingDirection};

$doc->setViewerPreferences(
    ViewerPreferences::create()
        ->hideToolbar()                                       // boolean flags default to true
        ->displayDocTitle()
        ->printScaling(PrintScaling::None)                    // ::AppDefault
        ->duplex(Duplex::FlipLongEdge)                        // ::Simplex, ::FlipShortEdge
        ->nonFullScreenPageMode(NonFullScreenPageMode::UseOutlines)
        ->readingDirection(ReadingDirection::LeftToRight)     // ::RightToLeft
        ->numCopies(2)
);
```

Uncommon keys (`/ViewArea`, `/PrintPageRange`, …) are available via `->set($key, $value)`.

### PDF/A archival conformance

[](#pdfa-archival-conformance)

```
use Papier\Metadata\PdfAConformance;

$doc->enablePdfA(2, PdfAConformance::Basic);      // sRGB OutputIntent + XMP pdfaid
$font = $doc->addFont(__DIR__ . '/Lato.ttf');    // fonts MUST be embedded
```

### Smaller files — object streams (PDF 1.5+)

[](#smaller-files--object-streams-pdf-15)

```
$doc->useObjectStreams();   // pack objects into compressed /ObjStm + /XRef stream
$doc->save('small.pdf');
```

### Font subsetting + searchable text

[](#font-subsetting--searchable-text)

```
// Embed only the glyphs that are used; a /ToUnicode CMap is generated
// automatically so the text stays searchable and copy-pasteable.
$lato = $doc->addFont(__DIR__ . '/Lato-Regular.ttf', subset: true);
```

### Incremental updates (edit without rewriting)

[](#incremental-updates-edit-without-rewriting)

```
use Papier\Writer\IncrementalUpdater;

$updater = PdfDocument::openForUpdate('in.pdf');     // preserves original bytes
$updater->updateObject($infoNum, $newInfoDict);      // override an object
$newNum = $updater->addObject($someDict);            // append a new object
$updater->save('out.pdf');                           // appends a /Prev revision
```

### Read and parse existing PDFs

[](#read-and-parse-existing-pdfs)

Reads classic xref tables, cross-reference streams, object streams, and hybrid-reference files. Encrypted documents (RC4, AES-128, AES-256) are decrypted transparently once the password is supplied.

```
use Papier\Parser\PdfParser;

$parser = new PdfParser(file_get_contents('document.pdf'));
$parser->setPassword('secret');                // for encrypted documents
$parser->parse();

echo $parser->getPageCount();                  // number of pages
echo $parser->extractText();                   // all text content
echo $parser->extractTextFromPageNumber(1);    // page 1 only
print_r($parser->getFonts());                  // font list
print_r($parser->getAnnotations());            // annotations
print_r($parser->extractImages());             // embedded images
print_r($parser->getPageInfo(1));              // page dimensions, resources
print_r($parser->getMetadata());               // title, author, subject, …
print_r($parser->getOutlines());               // bookmark tree
print_r($parser->getFormFields());             // AcroForm field values
print_r($parser->getAttachments());            // embedded file attachments
echo $parser->getXmpMetadata();                // raw XMP packet
```

Examples
--------

[](#examples)

The `examples/` directory contains 34 runnable scripts (two share the `16_` prefix):

FileDemonstrates`01_hello_world.php`Minimal document creation`02_text_formatting.php`Fonts, sizes, colours, alignment`03_graphics.php`Paths, shapes, gradients, clipping`04_images.php`JPEG/PNG embedding, `fromFile()`, alpha, scaling`05_forms.php`AcroForm fields`06_annotations.php`All 14 annotation subtypes (incl. redaction)`07_bookmarks_and_encryption.php`Outlines, password protection`08_advanced_graphics.php`Patterns, shadings, transparency groups`09_read_pdf.php`Parsing an existing PDF`10_optional_content_layers.php`Togglable layers`11_elements.php`High-level element API`12_multimedia.php`Embedded audio/video`13_transitions_and_media_elements.php`Page transitions`14_table.php`Tables with rowspan, footer, per-cell borders`15_ttf_fonts.php`Embedding TTF/OTF font files`16_import_pages.php`Importing pages from existing PDFs`16_table_utf8_alignment.php`Table column alignment with multi-byte (UTF-8) cell text`17_compressed_objects.php`Object streams + cross-reference stream (smaller files)`18_incremental_update.php`Editing a PDF via an appended revision`19_read_encrypted.php`Decrypting + reading outlines, forms, attachments, XMP`20_font_subsetting.php`TrueType subsetting and ToUnicode generation`21_unicode_cjk.php`Full-Unicode text via Type 0 (composite) fonts`22_mesh_shadings.php`Mesh shadings (types 4–7)`23_digital_signature.php`PKCS#7 digital signature via incremental update`24_pdf_a.php`PDF/A-2b archival conformance`25_xref_recovery.php`Recovering PDFs with a corrupt/missing xref`26_type3_font.php`Type 3 user-defined glyph fonts`27_shading_patterns.php`Filling shapes and text with gradient patterns`28_tagged_pdf.php`Tagged PDF / accessibility (PDF/A-2a)`29_text_extraction.php`ToUnicode-aware text extraction (accents, Type 0)`30_form_filling.php`Filling an existing AcroForm`31_ccitt_fax.php`CCITT Group 4 bilevel image compression`32_signature_appearance.php`Visible signature + document timestamp`33_page_operations.php`Headers/footers, merge, extract, N-up, rotateRun any example:

```
php examples/01_hello_world.php
```

Output PDFs are written to `examples/output/`.

Architecture
------------

[](#architecture)

```
src/
├── PdfDocument.php           Entry point — document, pages, fonts, metadata
├── Elements/                 High-level fluent API (Text, TextBox, Image, Table, …)
├── Content/ContentStream.php Low-level PDF operators
├── Annotation/               Annotation types (markup, widget, screen, …)
├── AcroForm/                 Interactive form fields
├── Font/                     Type1, TrueType, Type0/CID, font descriptors
├── Structure/                Pages, outlines, resources, transitions
├── OptionalContent/          Layers (OCG / OCProperties)
├── Multimedia/               Renditions, media play parameters
├── Encryption/               RC4 / AES password protection
├── Parser/                   PDF parser and text extractor
└── Writer/                   Low-level binary PDF writer

```

Licence
-------

[](#licence)

Papier is open-sourced software licensed under the [MIT license](LICENSE.md).

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance92

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~42 days

Recently: every ~18 days

Total

14

Last Release

48d ago

Major Versions

v1.4.2 → v2.0.02026-04-19

v2.1.0 → v3.0.02026-07-01

PHP version history (2 changes)v1.0.0PHP &gt;=8.0

v2.0.0PHP &gt;=8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/10746841?v=4)[Mikael Carlavan](/maintainers/mikaelcarlavan)[@mikaelcarlavan](https://github.com/mikaelcarlavan)

---

Top Contributors

[![mikaelcarlavan](https://avatars.githubusercontent.com/u/10746841?v=4)](https://github.com/mikaelcarlavan "mikaelcarlavan (589 commits)")

---

Tags

pdfpdf-generationphpphp-librarypdfPDF GENERATORPDF Readeriso32000pdf17

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/papier-papier/health.svg)

```
[![Health](https://phpackages.com/badges/papier-papier/health.svg)](https://phpackages.com/packages/papier-papier)
```

###  Alternatives

[barryvdh/laravel-dompdf

A DOMPDF Wrapper for Laravel

7.3k104.2M443](/packages/barryvdh-laravel-dompdf)[tecnickcom/tcpdf

Deprecated legacy PDF engine for PHP. Use instead tecnickcom/tc-lib-pdf.

4.5k112.8M622](/packages/tecnickcom-tcpdf)[mpdf/mpdf

PHP library generating PDF files from UTF-8 encoded HTML

4.7k85.8M608](/packages/mpdf-mpdf)[knplabs/knp-snappy

PHP library allowing thumbnail, snapshot or PDF generation from a url or a html page. Wrapper for wkhtmltopdf/wkhtmltoimage.

4.5k73.8M65](/packages/knplabs-knp-snappy)[spatie/browsershot

Convert a webpage to an image or pdf using headless Chrome

5.2k38.5M189](/packages/spatie-browsershot)[smalot/pdfparser

Pdf parser library. Can read and extract information from pdf file.

2.7k43.1M316](/packages/smalot-pdfparser)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
