WKHTMLtoPDF: Bad Kerning on AWS Lambda
June 28, 2019    |    AWS    |    Bug

Post-Mortem:

  • 3.5 Hours
  • One 4 year old Github issue
  • 1 obscure blog post about something else that helped

I recently wrote an article about how to create a PDF generator API on AWS Lambda using Serverless, Python3, and WKHTMLTOPDF. Building a PDF Generator on AWS Lambda with Python3 and wkhtmltopdf. Sorry for all the acronyms. The very next day I noticed that the kerning (letter spacing) of all the fonts on the generated PDFs we really odd looking. Actually, it was awful. Here is an example of the kerning problem. The left is how the font should look, the right is how the font looked before applying the solution. Notice how oddly spaced the letter are on the right.

Oddly spaced letter on generated PDF
Example 1 of bad kerning
Example 2 of bad kerning

It turns out that a system level configuration called fontconfig, which is built into linux based OSs, was creating causing a negative effect on the rendering of fonts.

When I first discovered this font issue, I immediately found a solution from AWS forums. The same solution was on Stackoverflow. The problem was that it didn’t work. The solution did work for some people, but not for me. This was the beginning of a 3.5 hour bug tour.

I ended up finding a very helpful Github issue:

https://github.com/wkhtmltopdf/wkhtmltopdf/issues/45

This is an amazing issue and great example of people working together to solve a problem on Github. @dandersson really did a great job explaining the problem and investigating the issue. The heart of the issue ended up being an OS level font rendering issue.

FontConfig?

Most solutions I found pointed to fontconfig, but there wasn’t a cohesive solution for my particular situation. I tried many things and almost gave up on wkhtmltopdf and Lambd, but before I did, I found this blog post about font kerning on debian:

https://www.internalpointers.com/post/fixing-ugly-fonts-chrome-chromium-debian-xfce

This article helped me solve the problem by providing the correct fontconfig file: (font.conf) This configuration below tells the OS not to use “Hinting” which was the real cause of the kerning issue I saw on my generated PDFs. Font hinting is the mathematical way to tell the OS how to render the letter in a grid. (See Wiki) . Once I applied this to my Serverless project, the letter spacing looked great.

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <match target="font">
    <edit name="antialias" mode="assign"><bool>true</bool></edit>
  </match>
  <match target="font">
    <edit name="hintstyle" mode="assign"><const>hintnone</const></edit>
  </match>
  <match target="font">
   <edit mode="assign" name="hinting"><bool>false</bool></edit>
  </match>
</fontconfig>

Serverless Configuration

The fontconfig above works, but also need to tell Lambda where this font.conf file lives. Specify the the location of the font.conf file in the serverless.yml file like so. In your Serverless root you should have ./fonts/font.conf.

service: pdfGen

frameworkVersion: ">=1.2.0 <2.0.0"

provider:
  name: aws
  runtime: python3.6
  environment:
    # Set env config for fonts to help with kerning
    FONTCONFIG_PATH: '/var/task/fonts'
    FONTCONFIG_FILE: '/var/task/fonts/fonts.conf'

Once I added this to my Serverless application the fonts looked 100% better and I was finally able to move forward. I hope is that this saves you some time figuring this out.

Thanks for reading.