fonts How to use OTF, TTF or PFB fonts in groff

You can add other fonts for use in groff. Use this script to convert TTF, OTF or Type1 fonts for use with groff documents.

I'll explain step by step the process to convert OTF, TTF or PFB fonts to a format usable by groff. For TTF there are also pdftex utilities you can use (ttf2afm and ttftotype42), but I got a better result using FontForge.

Prepare your environment

There are two tasks that I leave to you to solve yourself. First, you'll need to install FontForge in your system. Second, you need to find out where your system installs groff files. For this tutorial I'll use the default location at /usr/local/share.

For this example, I'll use George Duffner's EB Garamond, the font I used in my novels. You can download its nightly build from this link. First, create a directory to unzip the files. Once you unzip it, you'll get the whole font set in both OTF and TTF formats.

$ mkdir fonts
$ unzip Downloads/ -d fonts
$ ls fonts

Let's work with the EBGaramond12-Regular.otf file. You can also use the TTF one and get the same result. First, we'll need to prepare the environment. I prefer to avoid modifying system files, so to install the imported fonts, we'll create a directory in our home directory. I'll use the same directory I use in my system:

$ mkdir -p ~/.local/share/groff/site-font/{devps,devpdf}

To tell groff to look for fonts in our optional directory, we need to add the path to the GROFF_FONT_PATH variable. If you want to make this change permanent, you need to add the following command to your ~/.profile (or alternatively to ~/.bashrc or ~/.kshrc, depending on which shell you use):

$ export GROFF_FONT_PATH=$XDG_DATA_HOME/groff/site-font

Convert the font

The first step is to convert the OTF font to PFA format using FontForge:

$ cd fonts
$ fontforge -lang=ff -c "Open(\"EBGaramond12-Regular.otf\");Generate(\"EBGaramond12-Regular.pfa\");"

Besides the PFA font, the last command will also generate a second file, an AFM font. (From now on, we'll use ~/fonts as our working directory.)

$ ls EBGaramond12-Regular.* | grep -vE 'otf|ttf'

Now we'll use the AFM file and keep the PFA one for later. The next step will be to convert the .afm file to a groff format using afmtodit(1), but this command needs to read two files: text.enc and textmap. You should find these in your current installation of groff, but first let's copy them also to our working directory:

$ cp /usr/local/share/groff/current/font/devps/text.enc ~/fonts
$ cp /usr/local/share/groff/current/font/devps/generate/textmap ~/fonts

And then run the command:

$ afmtodit -e text.enc EBGaramond12-Regular.afm textmap GaramondR

The last argument from the afmtodit command, GaramondR, is the name I chose for the groff font. The suffix R stands for Roman. That suffix is mandatory. The full name should use the format <name_you_chose>‌(R|I|B|BI), where the suffix should be one of:

  • R (for Roman)
  • I (for Italic)
  • B (for Bold)
  • BI (for BoldItalic)

Check also that the name you choose is not already in use:

$ ls /usr/local/share/groff/current/font/devps/*R

Make final adjustments

Our recently created GaramondR file could use one last edit. Depending on the file we convert the font from, in some cases (as it is with this font) we need to add a ligatures fi fl 0 line manually, right above the kernpairs line. You can open the file with your preferred text editor and edit it yourself, or you can run the following command:

$ grep -q ligatures GaramondR || sed -i '/kernpairs/i\
ligatures fi fl 0\
' GaramondR

With that, the groff font is ready to be added to our custom directory, under the devps subdirectory:

$ cp GaramondR ~/.local/share/groff/site-font/devps/

But, for the font to get rendered correctly, we need to perform one more conversion with fontforge and copy the resultant Type 42 file to our devps directory:

$ fontforge -lang=ff -c "Open(\"EBGaramond12-Regular.otf\");Generate(\"EBGaramond12-Regular.t42\");"
$ cp EBGaramond12-Regular.t42 ~/.local/share/groff/site-font/devps/

Add the font to groff

To tell groff to use this file, we need to add the information to a download file in that same devps directory. If this is our first font, we'll need to create the file first:

$ printf "EBGaramond12-Regular\tEBGaramond12-Regular.t42\n" >> ~/.local/share/groff/site-font/devps/download

The above would be enough to generate a PostScript file. If you wish to make the font also available to gropdf, you can make a symbolic or "soft" link for the same groff font we added to the devps directory, but to the devpdf one:

$ ln -s ~/.local/share/groff/site-font/devps/GaramondR ~/.local/share/groff/site-font/devpdf/

For gropdf, as a complementary file instead of the Type 42, we'll add the PFA one we generated at the beginning of this tutorial with the first fontforge command:

$ cp EBGaramond12-Regular.pfa ~/.local/share/groff/site-font/devpdf/

As we did in our devps directory with the Type 42 file, to tell gropdf to use the PFA file, we need to add the information to a devpdf/download file, but in this case entries need to be prefixed with a Tab character. The leading \t in the following printf string will add a Tab character:

$ printf "\tEBGaramond12-Regular\tEBGaramond12-Regular.pfa\n" >> ~/.local/share/groff/site-font/devpdf/download

After completing all the above steps, we can set the font in our groff document with the following requests:

.fam Garamond    \" Font Family
.ft R        \" Font Type (Roman)

To add the rest of the font types you'll need to repeat the whole process. For Italic, use the EBGaramond12-Italic.otf file and GaramondI as the groff name. And so on for other font styles.

Putting it all together

To automate the whole process, you can add all of the above to a shell script:

# (c) 2023 Walter Alejandro Iglesias
# Convert and install OTF, TTF or PFA font to use it with Groff.  You need
# fontforge installed.

# Directory where you want the font installed (a custom path needs to
# be added to GROFF_FONT_PATH).  To install the font in the default
# system wide groff location just leave this empty (you'll need to run
# this script as root in this case).


if [ "`uname`" = "Linux" ]; then
if [ "$sitefont" = "" ]; then
    if [ "`whoami`" != "root" ]; then
        echo "You must be root to install the font in $sitefont"
        exit 1
elif [ ! -d $sitefont/devps ] || [ ! -d $sitefont/devpdf ]; then
    mkdir -p $sitefont/dev{ps,pdf}
if ! echo $1 | grep -E '.*(R|I|B|BI)+$' ||
  ! echo $2 | grep -E '\.(otf|ttf|pfb)$'; then
    echo "Usage: `basename $0` <groffname> <fontfile>.(otf|ttf|pfb)"
    echo "  groffname must be <name>(R|I|B|BI)"
    exit 1
which fontforge >/dev/null 2>&1 || {
    echo "This script uses fontforge to convert fonts"
    exit 1
name=`basename "$font" | sed -E 's/\.(otf|ttf|pfb)$//'`

fontforge -lang=ff -c "Open(\"$font\");Generate(\"$name.pfa\");"
fontforge -lang=ff -c "Open(\"$font\");Generate(\"$name.t42\");"
afmtodit -e $enc $name.afm $textmap $groffname
if ! grep -q '^ligatures' $groffname ; then
    sed -i '/kernpairs/i\
ligatures fi fl 0\
' $groffname
mv $name.t42 $groffname $sitefont/devps
mv $name.pfa $sitefont/devpdf
rm $name.afm
ln -s $sitefont/devps/$groffname $sitefont/devpdf/$groffname
printf "$name\t$name.t42\n" >> $sitefont/devps/download
printf "\t$name\t$name.pfa\n" >> $sitefont/devpdf/download

# End of