Fonts in node-canvas
Well, you’ll want to select a font, and that’s Really Hard.
node-canvas 2.0 will have a
ctx.registerFont() method that may supplant these instructions. In the meantime, here’s what you should do:
Here’s the nitty-gritty, for Linux and Mac OS X.
Make sure you’re using pango-cairo
Pango handles the tricky task of putting text in the right place. If you use node-canvas without Pango, you’ll get blocky and uneven text.
node-canvas can install without Pango. Avoid that.
Follow the node-canvas instructions: install pango before installing node-canvas. On Mac OS X,
brew install pango. On Ubuntu,
apt install libpango1.0-dev.
If you installed node-canvas after installing Pango, reinstall node-canvas:
rm -r node_modules/canvas && npm install canvas
Set FONTCONFIG_PATH and place fonts.conf there
There’s so much stupid history here.
When you open a web page that asks for “Helvetica” but you don’t have “helvetica.ttf” installed, your web browser may pick “arial.ttf” instead. There’s a font cache in your operating system that matches each font name to a file on disk.
node-canvas pretends to be an HTML5
<canvas>, so it mimics this absurdity. You’ve (hopefully) copied each font file into your project’s source, but by default, node-canvas won’t look there.
Configure the font cache, FontConfig (it’s cross-platform), to look for fonts in your project directory:
- Create a directory,
assets/fonts, and copy/paste the
fonts.conffrom above into it.
- Copy all font files for your project into
assets/fonts/. They should be
- Before using node-canvas, set the environment variable
FONTCONFIG_PATHto point to the directory that holds
fonts.conf. You can either do this in your shell (Bash:
FONTCONFIG_PATH=assets/fonts node render.js) or within your script (Node:
process.env.FONTCONFIG_PATH = './path/to/assets/fonts').
You can’t have
.. in your
FONTCONFIG_PATH. You may usesomething like
process.env.FONTCONFIG_PATH = require('path').resolve(__dirname, './assets/fonts') to remove all
If you misconfigure FontConfig, node-canvas will use your system fonts. That means different computers will render differently.
Force FontConfig on Mac OS X and Windows
Mac OS X and Windows don’t use FontConfig by default, and FontConfig is how we’re configuring fonts. Set the environment variable
fontconfig, either in your shell (Bash:
PANGOCAIRO_BACKEND=fontconfig FONTCONFIG_PATH=assets/fonts node render.js) or within your script (Node:
process.env.PANGOCAIRO_BACKEND = 'fontconfig').
If you don’t set
PANGOCAIRO_BACKEND, your font configuration won’t apply everywhere. Different computers will render differently.
<canvas> way of setting a font is to call
ctx.font = 'bold 30px Helvetica';. node-canvas mimics that, but it doesn’t do what your browser does and it can fail (for instance, if your font names contain commas).
Skip the middle-man. Use
ctx._setFont(weight, style, size, 'px', family) every time.
ctx.addFont(): it circumvents Pango.
Debug with FC_DEBUG, fc-match, fc-list and pango-view
All that’s left is to check font names (which are not filenames), weights, styles, sizes … and the environment variables you created above.
First, test you’re using FontConfig. Set the environment variable
FC_DEBUG=8191 before you run your script. Your script will output screens and screens of font debugging information. If it doesn’t, you aren’t using pango-cairo and FontConfig: that’s your bug. Fix it.
Once you’ve confirmed you’re using FontConfig, you can set
FC_DEBUG to various values for all commands in this section.
Make sure a font name maps to the correct font file:
FONTCONFIG_PATH=assets/fonts fc-match 'Proxima Nova Condensed'
The first line of output is the font file pango will use for the given name.
To find a list of candidate names, run this:
pango-view to quickly check that a font renders correctly. Here it is on Linux:
FONTCONFIG_PATH=raw-data/fonts pango-view --font='ProximaNova Condensed Extra Bold 20' -t 'Hello, world'
On Mac OS X, you’ll need X to make
pango-view actually show something.
brew cask install xquartz && brew reinstall cairo --with-x11 --build-from-source && brew reinstall pango --with-x11 --build-from-source && brew reinstall imagemagick — with-x11 — build-from-source (in that order), launch xQuartz, then prepend
PANGOCAIRO_BACKEND=fontconfig to the command above.
My parting thoughts
At this point, you probably realize that node-canvas is nothing like HTML5
<canvas>. Oops. But there is a cross-platform way to use fonts.
Incidentally, you can use all this advice (minus the
_setFont()) in Ruby and Python code, too.