01 — Build

Make a PDF from nothing.

A one-page document is eight lines. The same objects — pages, fonts, text, paths, images, fields — can compose a 400-page catalog, and the parser will take HTML if you would rather write markup.

01

Simple generation

No template language, no config, no rendering engine. Make a document, add a font, add a page, put text on it.

To send it to the browser instead of disk, swap the last line for Pdf::outputToHttp().

Simple generation in the docs →
hello.php
use Pop\Pdf\Pdf;
use Pop\Pdf\Document;
use Pop\Pdf\Document\Page;

$document = new Document();
$document->addFont(Document\Font::ARIAL);

$page = $document->createPage(Page::LETTER);
$page->addText(
    new Page\Text('Hello World', 12),
    Document\Font::ARIAL, 50, 742
);

Pdf::writeToFile($document, 'hello.pdf');
02

Advanced generation

Named styles so a type change is one edit. Images that resize on the way in. Compression on a flag. And an origin you can move to the top left, if PDF’s bottom-left math isn’t how you think.

Letter, Legal, Tabloid, A0–A9, B0–B10, envelopes, or any custom size
Page management as methods — copy, reorder, delete
Text alignment and wrapping inside a bounding box
Documents and pages in the docs →
report.php
use Pop\Pdf\Pdf;
use Pop\Pdf\Document;
use Pop\Pdf\Document\Font;
use Pop\Pdf\Document\Page;

$document = new Document();
$document->addFont(Font::ARIAL)
    ->setCompression(true)
    ->setOrigin(Document::ORIGIN_TOP_LEFT);

// one style, referenced everywhere
$document->createStyle('body', Font::ARIAL, 12);

$page = $document->createPage(Page::LETTER);
$page->addText('Q3 Results', 'body', 50, 50);

$image = Page\Image::createImageFromFile(
    'chart.jpg'
);
$image->resizeToWidth(320);
$page->addImage($image, 50, 300);

Pdf::writeToFile($document, 'report.pdf');
03

Simple & complex fonts

The standard 14 fonts are built in and ship with every reader. Embed TrueType, OpenType or Type1 and they compile as composite CID fonts with a /ToUnicode CMap — so non-Latin text renders correctly and still copies and extracts.

A missing glyph throws at compile time, naming the font and the character — not mojibake in production.

Fonts in the docs →
fonts.php
use Pop\Pdf\Pdf;
use Pop\Pdf\Document;
use Pop\Pdf\Document\Font;
use Pop\Pdf\Document\Page;

$document = new Document();
$page = $document->createPage(Page::LETTER);

// standard — no font file needed
$document->addFont(Font::HELVETICA_BOLD);

// embedded — any font beyond the standard 14
$font = new Font('/path/to/DejaVuSans.ttf');
$document->embedFont($font);

// embedded fonts support non-Latin characters
$page->addText(
    new Page\Text('123 ПРИВІТ:', 36),
    $font->getName(), 50, 600
);

// measure before you place
$width = $font->getStringWidth('Hello', 12);

Pdf::writeToFile($document, 'fonts.pdf');
04

Annotations & links

Link out to a URL, or jump to a page, coordinate and zoom level inside the same document — which is what a generated table of contents needs.

Annotations in the docs →
links.php
use Pop\Pdf\Pdf;
use Pop\Pdf\Document;
use Pop\Pdf\Document\Font;
use Pop\Pdf\Document\Page;
use Pop\Pdf\Document\Page\Annotation;

$document = new Document();
$font = new Font(Font::ARIAL);
$document->addFont($font);
$page = $document->createPage(Page::LETTER);

// external — hotspot sized to the text
$text = 'Example';
$page->addText($text, Font::ARIAL, 50, 742);
$url = new Annotation\Url(
    $font->getStringWidth($text, 12), 15,
    'https://example.com/'
);
$page->addUrl($url, 50, 742);

// internal: page 2, at 110% zoom
$text = 'Page 2';
$page->addText($text, Font::ARIAL, 50, 700);
$link = new Annotation\Link(
    $font->getStringWidth($text, 12), 15,
    10, 752
);
$link->setPageTarget(2)->setZTarget(1.1);
$page->addLink($link, 50, 700);

// the page that link jumps to
$document->createPage(Page::LETTER);

Pdf::writeToFile($document, 'links.pdf');
05

Drawing paths

Vector graphics, not a bitmap pasted on top. Lines, rectangles, rounded rectangles, polygons, ellipses, arcs, chords and pies, with fill, stroke, dash and clipping styles.

Enough to draw charts, rules, watermarks and callouts without leaving PHP.

Paths in the docs →
paths.php
use Pop\Pdf\Pdf;
use Pop\Color\Color;
use Pop\Pdf\Document;
use Pop\Pdf\Document\Page;

$document = new Document();
$page = $document->createPage(Page::LETTER);

$path = new Page\Path(Page\Path::FILL_STROKE);

$path->setFillColor(Color::rgb(155, 20, 20))
    ->setStrokeColor(Color::rgb(81, 125, 153))
    ->setStroke(5)
    ->drawRectangle(50, 400, 320, 240)
    ->drawCircle(210, 520, 60);

$page->addPath($path);

Pdf::writeToFile($document, 'paths.pdf');
06

HTML‑to‑PDF

Render HTML and CSS into pages without a headless browser. Render your template however you already do, and pass the string straight in.

Got a file on disk with linked stylesheets and images instead? Pdf::importFromHtmlFile() takes the path.

colspan, rowspan, and header rows that repeat across page breaks
Borders and background colors on any element, not just cells

Known limits: no border-collapse, no nested tables, and less common CSS may not be covered.

HTML parsing in the docs →
invoice.php
use Pop\Pdf\Pdf;

// however you already render templates
$html = '<h1>Invoice 1234</h1>';

$document = Pdf::importFromHtml($html);

Pdf::writeToFile($document, 'invoice.pdf');
07

Forms

Fillable PDFs, generated. Text, multiline, single- and multi-select choice, combo, push-button and radio fields, attached to a named form on the document.

Reader support for form fields varies. Adobe’s readers are the reliable target.

Forms in the docs →
form.php
use Pop\Pdf\Pdf;
use Pop\Pdf\Document;
use Pop\Pdf\Document\Font;
use Pop\Pdf\Document\Page;

$document = new Document();
$document->addFont(Font::ARIAL);
$page = $document->createPage(Page::LETTER);

$form = new Document\Form('contact');
$document->addForm($form);

$name = new Page\Field\Text('name');
$name->setWidth(200)->setHeight(20);

$page->addText('Name', Font::ARIAL, 50, 725);
$page->addField($name, 'contact', 50, 700);

Pdf::writeToFile($document, 'form.pdf');