Besting PhantomJS Font Problems

PhantomJS promises so much. It’s a headless webkit-based browser that is scriptable using a node-like dialect of Javascript

However, the promise dissolves in practice often times. Like many developers, I use a Mac as my workstation. Most servers I work with are Linux (Ubuntu) based. OS X and Linux sharing a common ancestor and philosphy means that 99.9% of the commands at a terminal are the same. The other 0.1% are well documented. Then there is PhantomJS.

PhantomJS on OS X renders beautiful images. A lot of this comes down to fonts — Steve Jobs was famously obsessed with fonts and it shows in OS X. Kerning is nice, there are generous in-built fonts. I’m not a font-head but I am visual and I can see the difference between Arial, Droid Sans and Helvetica.

The development process for both server and client side is to start out on your local machine. Developing on a live server is such a bad idea that I won’t even get into it. So, when working with PhantomJS, I do the same. Install PhantomJS on my OS X machine, installed the same version on my Ubuntu based DigitalOcean droplet. Then build my PhantomJS script and upload it.


The Story of a Word Cloud

I wanted to build a word cloud to automate some social media marketing I had been doing. In short, I’m generating a word cloud from the keywords in all my tweets from the previous day.

I decided to use D3 and the D3 Word Cloud plugin. I based my tool off of the example in the plugin and get it running in the browser. I wrote a little PhantomJS script to capture the image as a PNG and move on. The D3 Word Cloud plugin is async, so I need to account for that — so I put a setTimeout in. This is going to be run from a cron job and not an active server so I don’t feel bad about it. I’m capturing a beautiful PNG on my Mac.

Upload it to the server and give it a whirl. I got this disaster:

Image for post
Image for post
This is not the font I was looking for.

While the script executed correctly, this was definitely notwhat I was going for.

The word cloud script was using ‘Impact’ as it’s font. This seems like a pretty standard font for word clouds due to it’s geometric nature and ubiquity (as it’s part of the Microsoft “Core fonts for the Web” project). Evidently, PhantomJS doesn’t come with this font.

It didn’t absolutely have to be ‘Impact’ so, I thought I’d just find a similar looking font in Google Web Fonts and go forward. So, I embed css snippet and change the word cloud script to use the alternate font. The result?

Same terribleness.

Googling “PhantomJS webfont” and you’ll get a mix of broken or shady links (downloading a linux binary from some dude’s Google Drive…. uh no.) and bug reports with other developers shouting that it doesn’t work. Going deeper, you’ll find tantalizing reports of quick fixes — tweaking the supplied CSS, using different formats and so on. None of these actually worked for me, despite dumping a half day into them.

SlimerJS is a nearly PhantomJS compatible automated version of the Gecko (Firefox) engine. I ran into two issues with SlimerJS. First, I realize that it can’t load a local file and run it. It can easily capture a remote site but seems to be unable to load a html file sitting in the same directory. The other issue was a bit of a surprise: I was under the impression that it was headless just like PhantomJS. I ran my script through it and it starts opening new windows on my Mac. Further reading yields that SlimerJS isn’t (yet) headless. To run it headless, you’ll need xvfb, which is a headless implementation of X-Windows. No thanks. I don’t need that on my server.

I ran into the article Lessons learned while wrestling with Ubuntu fonts from a similarly frustrated developer. Finally — I thought — someone with a detailed solution instead of just a bug report. I ran through his solution and upload a truetype version of Impact to: ‘/usr/share/fonts/truetype’ and the run ‘fc-cache -fv’ and check if my font is found using ‘fc-match “Impact”’ and it works!

Now, on to testing PhantomJS. Guess what? Same cruddy font. It didn’t work, but I’m now finding where fonts are located on my server.

I learned that fonts are stored in the ‘/usr/share/fonts/’ directory from there it is sorted by type — ‘/usr/share/fonts/truetype/’ and ‘/usr/share/fonts/type1’. Looking in the ‘type1' subdirectory, I notice that there is a subfolder called ‘gsfonts’, I know that GhostScript is the web driver implementation that PhantomJS bundles in. Does ‘gsfonts’ stand for GhostScript Fonts? What would happen if I put a type 1 version of Impact into the ‘/usr/share/fonts/type1’ folder?

Success is what would happen.

Image for post
Image for post
  1. Get a Type1 version of the font you need. I needed to do a conversion from TrueType— there are lots of tools to do this with.
  2. Upload your Type1 font to your ‘/usr/share/fonts/type1' directory.
  3. Run ‘fc-cache -fv’
  4. Enjoy having PhantomJS with your new font.

Written by

Developer of things. Node.js + all the frontend jazz. Also, not from Stockholm, don’t do UX. Long story.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store