Ramblings of a Tampa engineer

Lately I've been obsessed with PDFs and how you produce them while working in a PHP project and the more I dig and learn - the more stressed I feel.

So I started to refresh my knowledge on a basic search of "pdf" on Laravel packages (Packalyst) and decided to pluck out a few near the million download mark to review.

Of course I was curious what tools under the hood these all used. It took a bit, but those same packages break down to:

Dompdf
An interesting PHP based package that wraps 3 different drivers, but defaults to CPDF.

  • CPDF by Wayne Munro
  • PDFLib by Apryse ($$$)
  • GD by PHP

Snappy
A PHP library that wraps wkhtmltopdf, which has sadly been abandoned at this point in time. Such a revolutionary package in its time (2008) as it created a headless way to take HTML to PDF with QtWebKit. The amazement with this timing and package is Chrome didn't get this feature until late 2017. Unfortunately a package built on WebKit in 2008 has decayed quite heavily and won't stand up to some of the more modern CSS features.

Browsershot
This PHP package leverages Puppeteer to control/manage Google Chrome - an attractive option to use a highly stable & tested option. With the amount of configuration required to get a working Chrome & Puppeteer within Docker made this a less attractive option to start with.

Laravel PDF
This package is a wrapper for mPDF, which appears to be a forked/modern iteration of FPDF. A pure PHP implementation, which has also fallen behind in the modern specifications of CSS.

So I really wasn't truly happy with my results so far and thus expanded it further with some Google searches. This led to finding more options such as:

  • Gotenberg - A docker-powered stateless API for PDF files.
  • Pop PDF - A modern PHP library for the PDF specification.
  • PrinceXML - Convert HTML to PDF
  • Typeset.sh - PDFs with PHP using HTML & CSS

So before I tried some out, I decided to toss some from my list immediately:

  • Snappy - Not building something against wkhtmltopdf - its been abandoned for years.
  • Browsershot - If I'm going to try one headless Chrome - it'll be Gotenberg.
  • Laravel PDF - If I'm going to try a pure PHP one - it'll be the 17~ million download one.
  • PrinceXML - Steep ($2,000) license cost, but I'll try the SaaS offering.

Thus with the remaining left - I decided to give them a whirl.


Dompdf ($?)

Amazing drop-in use with little to no configuration, but falls apart quickly with any complex HTML document.

Dompdf GitHub

I tested out Dompdf first and I was amazed with a Laravel application how with 0 dependencies outside of my existing installed Imagick - I ran one line of code and converted my HTML to PDF. Now the fun ended pretty quickly when I realized the alignment was busted majorly.

Digging into a project with 500+ open issues and all these workarounds I stumbled upon different adapters. Little did I know I was using the default CPDF, which is some 20+ year old PDF code that fell into public domain and has been patched over a decade. So I wanted to research the GD (PHP Image Extension) and PDFLib (Paid extension) for some comparison.

Very quickly I learned the GD extension refused to render more than 1 page, which I also had to install since I was running only Imagick. So I tossed that aside as I didn't really want to install GD and then fight with it.

The final adapter was PDFLib so I changed my config and generated a PDF and nothing changed - it was still authored by CPDF. So I checked the PDFLib website and saw they charged per server, including load balanced containers so I just skipped it before digging further into why my adapter switch didn't work. I didn't want to spend time on something that I knew was going to be an expensive option if I wanted to horizontally scale a solution across some containers.


pop-pdf

A refreshed from scratch modern PHP implementation of the PDF specification. However with 1 contributor and not much traction tough to trust for prime time.

POP PDF Docs

After slamming my head against a wall trying to use all these older CSS tricks to position images with dompdf - I wanted to go in a completely different direction and try out an implementation that just had an API for direct PDF manipulation. The API looked quite sane and attractive to try out.

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

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

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

However, pretty quickly after the docs saying one thing and my code saying another. I felt this project was just way too new to try out. However, its not fair to say new when this project has been around since 2014. It just hasn't gotten the popularity that other PHP frameworks have which help refine its API.

Perhaps in time if adoption occurs and framework growth - this may become a powerful little piece of PHP software for direct PDF drawing.


DocRaptor ($)

A SaaS offering of the Prince software which works very well with modern CSS features, but you pay per document generated.

DocRaptor Website

So after trying out some free software - I wanted to break into the paid software realm to test out the difference of features. Immediately it was a night & day difference of the HTML generated. Features I was unaware were stripped in my previous solutions were rendered with pixel perfect accuracy.

However, knowing I wanted to generate some large PDFs full of images - it seemed the SaaS offering was just a bit too expensive and limited for what I wanted to do. I once again didn't want to dive further into integration with a platform when the cost barrier would rise high until I eliminated all my other options.


Gotenberg

A docker container powering queue systems for headless Chrome, LibreOffice and various other PDF engines. Pack full of configuration and excels at any task.

Gotenberg Website

Once I got a successful run on Gotenberg I believe I found my winner. The documentation started with a very basic sample with a CURL command.

curl \
--request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://my.url \
--form landscape=true \
-o test.pdf

It booted up Chrome and handled all the stress that I previously encountered when it was my responsibility to wire up Chrome with another option. Just like that a PDF was generated and it looked pixel perfect - holding the power of the large Chromium behind it.

As I ramped up the pages and the image count - it offered an asynchronous mode and built in queue system. Having these features built in were amazing as you could queue up many document converts and let it do the rest - sending a webhook when done.

As I configured this service further I loved the configuration it offered. Don't use LibreOffice? Just don't start it - so the container remains quite slim with memory use to only what you are using.

Scaling horizontally with many containers couldn't be easier and with a $0 price tag and over 40 million downloads - it seems like others agree.


Typeset.sh ($)

A PHP solution with not much documentation, but a demo that shines with flexibility and features.

Typeset Website

At this point I was pretty solidified on Gotenberg, but I had to push forward to try my final option. As I extracted my HTML from the previous solution I shoved it into Typeset's demo and a few seconds later I had a fairly amazing looking PDF. A test 2x2 image grid looked malformed and pushed onto a new page, but otherwise looked crisp and clean.

However, knowing I had a $0 option and this holding a price tag I wasn't going to spend much effort on it. It may very well be a cheap professional option compared to the offerings of say Prince, but neither of those presently could compare to Gotenberg.


All in all if you scroll to the bottom of this. Gotenberg is the way to go and my winning HTML to PDF solution. It surpassed my expectation in every test and was easily configured in both deployment and local usage.

You’ve successfully subscribed to Connor Tumbleson
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Success! Your email is updated.
Your link has expired
Success! Check your email for magic link to sign-in.