How to install custom fonts on a nodejs image using fontconfig

I recently had to generate a custom image from a Node.js backend, and I chose to use Sharp to take an SVG and convert it into a PNG, since we were already using Sharp and it seemed like the most feasible thing to do.

However, I found it a bit less unintuitive how to add custom fonts to the rendered image. I found that locally - given I had the required font installed on my OS - it would work just fine. However, in production font's wouldn't load correctly.

So I thought I'd write this step-by-step guide because that's what I was missing when researching this.

libvips and Sharp

So Sharp is responsible for rendering the PNG based on the SVG, and Sharp uses libvips which uses librsvg under the hood which uses fontconfig (yeah, good luck on that documentation).

So the thing to do is:

  1. Ensure fontconfig is installed
  2. Ensure your fonts are valid, in the correct format and present in the environment

Uploading your fonts

What I did was to create a fonts folder inside my project root (feel free to place this wherever you see fit), and then ensure that this folder is copied to the correct location when building the image.

Another thing to note is that initially I tried with .otf fonts, however, that didn't seem to work, so I instead converted them to .ttf using cloudconvert.

Next step is to ensure fontconfig is installed in your environment.

Installing fontconfig in your Dockerfile

I use Docker to build my applications, so I changed my Dockerfile to look something like this:

FROM node:16-bullseye-slim AS production

COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build --chmod=755 /usr/src/app/fonts ./usr/local/share/fonts
RUN apt-get update; apt-get install -y fontconfig
RUN fc-cache -f -v

This will:

  1. Copy the fonts folder in your project root to /usr/local/share/fonts (which is one of the locations fontconfig will look for fonts)
  2. Install fontconfig and clear any font cache - which might not be needed, but is a cheap thing to do.

You can also exec/ssh into your running instance and install fontconfig using: apt-get update; apt-get install -y fontconfig. Afterwards you may run fc-cache -f -v to find out where exactly fontconfig tries to look for fonts (thats how I found /usr/local/share/fonts).

That's it. Afterwards my custom fonts were rendering correctly. My SVG would look something like this:

<text font-family="Cera Pro" font-size="44" font-weight="500">

Debugging

If you're still having issues try these steps:

  1. Run fc-list this will list which fonts fontconfig have found
  2. You may need a fonts.conf file inside your fonts folder (I did seemingly not need that)
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
	<dir>/fonts</dir>
	<config></config>
</fontconfig>
  1. Try to validate your font
  2. Feel free to comment in the comment section and I shall try to help out

Comments