One requirement during the development of a client’s e-commerce site was the creation of dynamic, customizable bag labels for their equally dynamic and customizable dog food. The custom labels displayed pet and owner names, custom images, breed and gender specific phrasing, variable ingredients, and colors.
The first option we investigated was using Zend_PDF, which Magento already uses to generate shipment labels. With Zend_PDF, we would have needed to programmatically set the X, Y, size, etc., parameters of any element on the page, like this:
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_TIMES);
$page->drawText(‘example text here’,100,($page->getHeight()-100));
Because of the complexity of the label design, we decided to use an HTML to PDF generator, instead. This allowed us to design our labels like we would design a webpage and then rely on our HTML to PDF tool to convert our webpages into the PDF that would become the printed label. This allowed us to quickly iterate on design changes and provided much greater flexibility.
After trying a few converters, we decided to use wkhtmltopdf. The setup process was fairly simple.
- We downloaded and installed the latest version, making sure the apache user had permission to run the wkhtmltopdf binary (e.g. “chmod 777 /usr/bin/wkhtmltopdf”).
- After running some tests, we noticed that our custom fonts in the rendered PDF were not getting processed correctly and were falling back to default fonts such as Arial and Times New Roman. To fix this, we installed the TTFs of our custom fonts on the server.a. On CentOS, this required moving the TTFs into /usr/share/fonts and running “fc-cache -f -v”. Wkhtmltopdf could then detect and use the custom fonts.
We wanted the labels to be generated automatically as they came in for every new order. We created a cron job model to pick up the new orders and generate the PDFs using PHP’s shell_exec to call Wkhtmltopdf. We noticed we were having problems with wkhtmltopdf being able to create PDFs from remote URLs, so our Magento cron job was configured to save the HTML to a file on the server which wkhtmltopdf could reference. Here’s the command we used with our wkhtmltopdf parameters:
$wkhtmlOutput = shell_exec(“/usr/local/bin/wkhtmltopdf -d 300 -L 0 -R 0 -T 0 -B 0 –page-height 19in –page-width 13in /tmp/tmp_label.html /tmp/tmp_pdf.pdf 2>&1”);
”2>&1” allowed us to retrieve any success or error output from wkhtmltopdf while “-d 300 -L 0 -R 0 -T 0 -B 0” are the parameters we needed to produce a print-ready PDF output.
The process required close work with the frontend engineers, backend engineers, and the printer staff, as well as a little trial and error to get everything working. In the end, we had an automated system to create custom labels based on the user’s input.
Difficulties and Restrictions from Using this Process
Units: Firstly, pixels don’t translate well to the print world. Where pixels are treated as “dots,” the DPI of a printer distorts their size and density vs. a screen. In other cases, functions are used which may change the size of an item rendered in pixels. To circumvent this issue, whenever possible we used inches and points in our CSS. This was a unique challenge for our frontend designer. Aside from print-stylesheet tweaks, we have worked mostly in ems, rems and pixels.
Image DPI: While high-density screens have become common on mobile devices, many screens and graphics are still low-res by print standards. We used JPGs whenever possible, because they can use CMYK color profiles, and ensured our images were oversized. We then shrunk the to the correct size in inches using CSS, resulting in high DPI images.
PDF Converter Constraints: The PDF converter we use did not fully support all CSS background settings. Because of this, we had to leverage absolute position and strict z-index values to place img tags in the background.
Fonts: Because the PDF generator was not making an HTTP request, we had to have local versions of all fonts, including Windows core fonts, on the server generating the PDFs. The fonts were referenced through a standard font-family CSS call, rather than as a web font.
Variable Length Text: Because we allowed custom pet and owner names, some considerations had to be taken for very long or short names. We used PHP to check the length of name strings and increase or reduce font sizes at certain lengths programmatically.
Bleed and Curling: The world of physical print is sometimes messier and less predictable than digital. To that end, our designs had to allow for the bleed – the color that breaks out of it’s designated area so labels have color right up to the edge – as well as the curling effect that was happening as the paper came through the printer, causing alignment to change slightly between prints. This was accomplished mostly through more spacing between elements and more outside padding; margins were avoided when possible because the padding produced more reliable results.
In October 2014, we started receiving wkhtmltopdf errors. This was because of a recent server change disabling SSLv3 in response to “SSLv3-Poodle” vulnerability. We were receiving “QAbstractSocket::connectToHost() called when already looking up or connecting/connected to www.site.com.” Upgrading to the testing version of wkhtmltopdf (wkhtmltopdf 0.12.2-6a13a51) fixed this problem.
Another alternative to wkhtmltopdf we looked into was the headless browser phantomjs. We haven’t investigated this alternative fully, but our guess is that it handles webfonts and remote URLs better than wkhtmltopdf.