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.
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 →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');
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.
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');
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 →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');
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 →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');
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 →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');
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.
Known limits: no border-collapse, no nested tables, and less common CSS may not be covered.
HTML parsing in the docs →use Pop\Pdf\Pdf; // however you already render templates $html = '<h1>Invoice 1234</h1>'; $document = Pdf::importFromHtml($html); Pdf::writeToFile($document, 'invoice.pdf');
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 →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');