Font FAQ

Before we launch into the gory details, we would like to explain why fonts are a hard problem. The naming and rendering of text fonts in Graphviz (and other programs) is complicated. There are several reasons:

  • Graphviz runs on a wide range of systems: Linux and other Unix variants, Microsoft Windows, and Mac.
  • Graphviz has a wide range of output formats: raster-oriented formats like PNG and GIF; path-based ones like Postscript, PDF and SVG; some idiosyncractic legacy formats, like troff PIC.
  • Often, output will be downloaded and displayed on a computer or other device, different than the one where the layout was created.
  • Graphviz layouts should be identical in size and appearance, regardless of the output format.
  • Graphviz can run on external libraries that help with naming and rendering text fonts, but they are not required, and stripped-down Graphviz tools can be built without them. In fact, Graphviz may have to run on systems with no font files installed.
  • There are several major font file formats to be supported.
  • Non-Western, international character sets should be supported.
  • Graphviz should provide a good set of standard fonts.
  • It should be easy to specify standard fonts.
  • Users should be able to load their own custom fonts.
  • Output should be small to download quickly.
  • Output should allow the best rendering possible in a given format.
  • Output files should be easy to postprocess, for example, retaining the objects of the original graph if possible.
  • It is very helpful to work around known bugs or missing features in support libraries and popular external tools.

This is a tall order. Some of the goals conflict. Generally our approach has been to define defaults that favor convenience and good looking output, and give the user options to override the defaults.

Overview

In the following, we will assume a "standard" version of Graphviz with the full set of support libraries (fontconfig, gd, Cairo and Pango), running on a desktop system or server with a standard installation of font files.

The graphviz layout engines (dot, neato, etc) create layouts with nodes sized to enclose the text labels. This requires knowing the size of the text blocks, which in turn requires knowing the metrics of the font glyphs and their composition into words, taking into account wordspacing, kerning, hinting, etc. So the overall process is: font specification, then text layout, followed by Graphviz output (and final rendering on the target display or device, which may or may not be by a Graphviz tool).

A font is usually selected by family name (fontname) and other properties (see below: "Font selection"). Then fontconfig matches the request to a system font.

Note: in older versions of Graphviz, fontname was simply a file name. This required exact file name matching (with a little bit of helpful name mangling under the hood, e.g. translating Times-Roman to Times, or Helvetica to Arial on Windows systems (and yes, we know there is a difference). Under fontconfig, fontnames are family names, which fontconfig matches to the closest font it finds. This always "succeeds", but unfortunately produces surprising results if fontconfig's idea of "close" doesn't match yours. This can happen when you specify a custom (or just nonexistent) font, like Steve-North-Handwriting, and fontconfig silently falls back to something safe like a typewriter font.

Text layout is performed by pango, which accepts text and computes a layout with metrics that determine node sizes.

Though line drawing is provided by cairo for many output formats (and likely more in the future), for raster output formats, font rendering is passed though cairo to freetype. Freetype is also called if gd is used for drawing. (gd can also be requested explicitly, e.g. dot -Tpng:gd, or by default when Graphviz is built without cairo). Freetype provides antialiasing, hinting, kerning, and other low-level font features.

Font metrics are obtained from the fonts installed on the system running Graphviz. Results are guaranteed when Graphviz outputs raster formats, because freetype immediately renders the fonts into pixels. On the other hand, with path-based formats like Postscript (-Tps) and SVG (-Tsvg), final rendering may be done on a different platform altogether, with different font files installed. Clearly, Your Milage May Vary. In the case of Postscript, the driver in Graphviz passes the expected metrics of the text block down to the renderer, and asks it to make a final stretch (or squeeze) to force the text to fit the metrics that were in effect at layout time. In Graphviz SVG, there is only a hope and a prayer that the SVG rendering program's fonts match the ones fontconfig and freetype used when Graphviz was run. (More about this later.)

Default fonts and PostScript fonts

The default font in graphviz is, and always has been, Times-Roman.

Graphviz has historically supported some "standard" Postscript fonts, initially, Times-Roman, Helvetica, Courier and Symbol. This list was later enlarged by Adobe to include 35 fonts, which are:

AvantGarde-Book AvantGarde-BookOblique AvantGarde-Demi
AvantGarde-DemiOblique Bookman-Demi Bookman-DemiItalic
Bookman-Light Bookman-LightItalic Courier Courier-Bold
Courier-BoldOblique Courier-Oblique Helvetica
Helvetica-Bold Helvetica-BoldOblique Helvetica-Narrow
Helvetica-Narrow-Bold Helvetica-Narrow-BoldOblique
Helvetica-Narrow-Oblique Helvetica-Oblique NewCenturySchlbk-Bold
NewCenturySchlbk-BoldItalic NewCenturySchlbk-Italic
NewCenturySchlbk-Roman Palatino-Bold Palatino-BoldItalic
Palatino-Italic Palatino-Roman Symbol Times-Bold Times-BoldItalic
Times-Italic Times-Roman ZapfChancery-MediumItalic ZapfDingbats

Unfortunately, fontconfig doesn't recognize PostScript-style font names directly, so Graphviz makes custom mappings from its list of PostScipt names into fontconfig family names for use in all cairo and gd based renderers. In -Tps output, these fonts are used without name translation.

Font selection

The fontname attribute in .gv graphs is a fontconfig style specification.

From: http://www.fontconfig.org/fontconfig-user.html

Fontconfig provides a textual representation for patterns that the library can both accept and generate. The representation is in three parts, first a family name list, second list of point sizes, and finally a list of additional properties:

<families>-<point sizes>:<name1>=<values1>:<name2>=<values2>...

Values in a list are separated with commas. The name needn't include either a family or point size; they can be elided. In addition, there are symbolic constants that simultaneously indicate both a name and a value. Here are some examples:

Name Meaning
Times-12 12 point Times Roman
Times-12:bold 12 point Times Bold
Courier:italic Courier Italic in the default size
Monospace:matrix=1 .1 0 1 The users preferred monospace font with artificial obliquing

Graphviz currently has a separate attribute for specififying fontsize.

TODO: We should allow the fontconfig style specification. Times-20 does not currently result in a 20pt font. This is probably because of special treatment of - for postscript font names.

TODO: We seem to have a bug with use of : in fontnames, probably because of special treatment for filenames in Windows. In fontnames, use <space> instead of : to separate values. -Nfontname="Courier:italic" doesn't produce an italic font in graphviz-2.16.1, but: -Nfontname="Courier italic" works, but -Nfontname="Monospace matrix=1 .1 0 1" doesn't.

Font management with fontconfig

How can I tell what fonts are available?

$ fc-list

How can I tell what fonts dot is using?

$ dot foo.gv -Tpng -o foo.png -v 2>&1 | grep font

How can I add a custom font?

In the current version of Graphviz with fontconfig, Cairo and Pango, this cannot be done by simply putting a file in the current directory or setting the DOTFONTPATH path variable. Your custom font must be explicitly installed by fontconfig tools.

For a single font, e.g., foo.ttf:

$ mkdir -p ~/.fonts
$ cp foo.ttf ~/.fonts/

One can run fc-cache to speed up the use of fontconfig.

$ fc-cache

For Windows users, one can go to the C:\windows\fonts folder and use File -> Install New Font from the pull-down menus to install the font.

For a new font directory, e.g., /Library/Fonts, add a new <dir> element

<dir>/Library/Fonts</dir>

to a .conf file. Note that the file must have a correct xml structure as specified by the fontconfig fonts.dtd. Possible choices for the .conf file are local.conf in the same directory as the system-wide fonts.conf file, or .fonts.conf in your home directory.

How can I ... font?

See: http://www.fontconfig.org/fontconfig-user.html

Can I specifiy a font by filename instead of by familyname?

Sorry, the answer is no. (The reason is that for this to work, Graphviz has to intercept the font lookup before fontconfig is called, and this can't be done when fonts are being looked up by Pango.)

Some versions of fontconfig appear to recognize pathnames and attempt to use that, but this isn't always the case.

How can I be sure that a specific font is selected?

Provide enough specification in the fontname, and test it with fc-match to ensure that your desired font is selected. (Note, this will not ensure that the same font is used in -Tps or -Tsvg renderings where we rely on the fonts available on the final printer or computer.)

Note the downside, as mentioned previously, is that Graphviz cannot do much to warn you when fontconfig didn't find a very good match, because fontconfig just cheerfully falls back to some standard font. It would be really nice if the fontconfig developers could provide a metric reflecting the quality of the font match in their API.

What about SVG fonts?

Graphviz has a native SVG driver that we wrote (which is the default), and cairo's SVG driver (which you get with -Tsvg:cairo).

Graphviz' native SVG driver generates Windows compliant names like Times New Roman or Arial by default. The names work in a lot of situations (like Firefox running on Windows), but are not guaranteed to be portable. If you set -Gfontnames=ps, you get Postscript names like Times-Roman. If you set -Gfontnames=svg you are guaranteed to get rock solid standards compliant SVG. The SVG standard says that the legal generic font names are Serif, Sans-Serif, and Monospace (plus Cursive and Fantasy which we don't use in Graphviz). We generate those names. The bad news is that various downstream renderers and editors may resolve the generic font names differently, so it's not quite clear how your SVG will look. Many W3C examples show how to use CSS (Cascading Style Sheets) to get around this problem by giving a list of font family names in order of lookup precedence, but some downstream processors (like the inkscape editor in Linux) don't implement CSS, so we're up a tree here.

The cairo SVG driver solves this in an effective though brute force way: it simply encodes embeds the needed fonts as lines and curves in the target SVG. For small examples, -Tsvg:cairo is about 10 times bigger than -Tsvg, but maybe it's worth it for correctness. The other problem is that such SVG is much much slower to render, no doubt because it bypasses any system font rendering services, and does it the old fashioned way.

What about Postscript fonts?

TODO: say something here. What about non-ASCII like Latin1? What about loading your own fonts via -L like in the old days with the weird outline font example.

"What if" issues for nonstandard Graphviz builds

The following only apply if you build your own version of Graphviz by configuring and compiling the source code to build your own custom executable. If you don't know what this means, it definitely does not mean you.

No freetype

When graphviz is built on systems without freetype, then only the gd renderer will be available for bitmap outputs, and the only available fonts are a small set of builtin bitmap fonts. The poor quality of these fonts will be evident, also, dot ... -v 2>&1 | grep font will say that the font is <internal>. This may actually be desirable for installing minimal graphviz programs on a server where fonts may not even be installed.

No fontconfig

If graphviz is built on systems without fontconfig (e.g. Redhat-7) then the fontname attribute will be interpreted as a font file name. The system directories will be searched for this, or the directories can be specified with the GDFONTPATH environment variable (or DOTFONTPATH for historical reasons). Graphviz will use gd and freetype to obtain metrics and render text. No pango/cairo renderers will be available without fontconfig support.

Disabling fontconfig

Pango/cairo depends on fontconfig, so to disable fontconfig you also have to disable pango/cairo. The easiest way to do this temporarily is to edit /usr/lib/graphviz/config and remove the entire libpango block.

Note that any changes to this file will be lost the next time graphviz is updated, or dot -c is run with installer privileges.

With pango disabled, graphviz will use gd which, even if it was built with fontconfig support, will still allow fontnames to be given as filenames.

You can also disable cairopango at build time with configure script options.

No gd

Cairopango works without gd. We are moving graphviz to the pango/cairo libraries, but gd still offers some features that are hard to replace, such as JPEGs, GIFs and paletted color bitmap outputs. However, font support is fully functional without gd so long as pango, cairo, fontconfig, freetype are available.

No pango/cairo

Without pango/cairo, some of the key renderers are only available with gd, which produces lower quality (but smaller) output.

Looking forward, we expect to depend more on pango for things like: line wrapping, multiple fonts per label, bidirectional text and other internationalization features.

No gd and no cairopango

This is basically the original Graphviz without any external fonts. It cannot render any raster formats, so it's mainly good for Postscript. It relies on a few internal font tables

Last modified September 12, 2022: Update font.md: remove reference to HPGL (6e5dd62)