Adding custom fonts to groff (+pandoc)

It's not easy, but it's easier than you might think! You'll need:

The latest versions of groff and ttf2pt1 are available in package repositories, including homebrew.

Converting and installing a font

We need to take a TrueType (TTF) font and convert it to a groff font file. To do this, we use groff's afmtodit utility. This won't convert from TTF directly, so we need to convert the TTF font to a PostScript Type 1 font first using Andrew Weeks et al.'s ttf2pt1.

You also need to locate your groff/share directory, which contains font/devps, the install directory. For a homebrew installation of groff, this will be $HOMEBREW_CELLAR/groff/*/share/groff/current.

Suppose we have Iowan.ttf, IowanBold.TTF, IowanItalic.TTF, and IowanBoldItalic.ttf. We need to move them somewhere convenient, like the ~/.fonts directory.

mkdir -p ~/.fonts
mv Iowan*.ttf ~/.fonts/.

Then convert each TTF to a PFA/AFM pair:

ttf2pt1 -a -e Iowan.ttf
ttf2pt1 -a -e IowanItalic.ttf
ttf2pt1 -a -e IowanBold.ttf
ttf2pt1 -a -e IowanBoldItalic.ttf

Next, switch to the groff postscript font directory devps:

cd $HOMEBREW_CELLAR/groff/1.22.4_1/share/groff/current/font/devps

(You may need to replace the directory name representing the version number.)

Then convert the AFM files to the native groff font format and store them in the devps directory:

afmtodit -e text.enc ~/.fonts/Iowan.afm textmap IR
afmtodit -e text.enc ~/.fonts/IowanItalic.afm textmap II
afmtodit -e text.enc ~/.fonts/IowanBold.afm textmap IB
afmtodit -e text.enc ~/.fonts/IowanBoldItalic.afm textmap IBI

Here is the naming convention: The prefix is up to you---I've chosen I for Iowan, but it doesn't even need to be a single letter. The suffix is standardised: R for regular/roman, I for italic, B for bold, and BI for bold-italic. In this example, you should end up with four files: IR, II, IB, and IBI, all in your groff/share/font/devps directory.

Note: The .pfa files need to remain in your ~/.fonts directory, or the font must be otherwise installed in your system's font manager.

Note also: You might think we could leave everything in ~/.fonts instead of moving files into groff/share/font/devps. Alas, setting the GROFF_FONT_PATH environment variable to the local .fonts directory also doesn't accomplish this for me, and I don't understand why. Mysteries.

Congratulations: your font is now available to groff and its macros using the short name you've just given it.

Using an installed font with pandoc

I use groff as the pdf engine for pandoc, a universal document format converter. So now, suppose I want my groff-typset PDFs to use Iowan as a font. Here's how to make that happen.

Easy mode

You can now set the font by passing -M fontfamily=I as an argument to pandoc.

Alternatively, you can include this in your markdown manuscript's YAML header block:

fontfamily: I

Advanced mode

Suppose you want all your documents to use your newly installe font of choice by default. Rather than specifying it in each document or each time you compile, you can (locally) modify pandoc's default ms template.

Pandoc looks for "custom" templates in two locations. If you have a ~/.local directory, it looks for ~/.local/pandoc/templates; and (only!) if you don't, it looks for ~/.pandoc/templates.

So let's create and populate the first directory with a modified groff/ms macro template.

mkdir -p ~/.local/share/pandoc/templates
pandoc -D ms >

Now edit using your editor of choice, changing this line (38):

.fam $if(fontfamily)$$fontfamily$$else$P$endif$

to choose I (Iowan) instead of P (Palatino):

.fam $if(fontfamily)$$fontfamily$$else$I$endif$

Now when you use pandoc to generate pdfs using the -T ms option, it will be typeset using your font of choice!

Note: If you specify the font on the command line or in the YAML block, that will take precedence over any changes you've made to the default template.

Note also: If this breaks your groff>pdf documents after a pandoc update, you may need to repeat the steps in this subsection. (The default ms template may have importantly changed, but pandoc will still be using your old, modified version.) However, the template seems to be very stable; I've never encountered this issue in several years of using this system.