Graphviz and fonts.
===================
Before we launch into the gory details, we would like to explain
why this is 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 and HPGL.
- 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:
-:=:=...
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 The users preferred monospace font
with artificial obliquing
Graphviz currently has a seperate attribute for specififying fontsize.
[ FIXME
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.
]
[ FIXME
We seem to have a bug with use of ':' in fontnames, probably because
of special treatment for filenames in Windows.
In fontnames, use 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 element
/Library/Fonts
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?
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 "". 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 priviledges.]
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