Daniel@0: Graphviz and fonts. Daniel@0: =================== Daniel@0: Daniel@0: Before we launch into the gory details, we would like to explain Daniel@0: why this is a hard problem. The naming and rendering of text fonts Daniel@0: in Graphviz (and other programs) is complicated. There are several reasons: Daniel@0: Daniel@0: - Graphviz runs on a wide range of systems: Linux and other Unix Daniel@0: variants, Microsoft Windows, and Mac. Daniel@0: - Graphviz has a wide range of output formats: raster-oriented formats Daniel@0: like PNG and GIF; path-based ones like Postscript, PDF and SVG; some Daniel@0: idiosyncractic legacy formats, like troff PIC and HPGL. Daniel@0: - Often, output will be downloaded and displayed on a computer or other Daniel@0: device, different than the one where the layout was created. Daniel@0: - Graphviz layouts should be identical in size and appearance, Daniel@0: regardless of the output format. Daniel@0: - Graphviz can run on external libraries that help with naming and Daniel@0: rendering text fonts, but they are not required, and stripped-down Daniel@0: Graphviz tools can be built without them. In fact, Graphviz may have Daniel@0: to run on systems with no font files installed. Daniel@0: - There are several major font file formats to be supported. Daniel@0: - Non-Western, international character sets should be supported. Daniel@0: - Graphviz should provide a good set of standard fonts. Daniel@0: - It should be easy to specify standard fonts. Daniel@0: - Users should be able to load their own custom fonts. Daniel@0: - Output should be small to download quickly. Daniel@0: - Output should allow the best rendering possible in a given format. Daniel@0: - Output files should be easy to postprocess, for example, retaining Daniel@0: the objects of the original graph if possible. Daniel@0: - It is very helpful to work around known bugs or missing features Daniel@0: in support libraries and popular external tools. Daniel@0: Daniel@0: This is a tall order. Some of the goals conflict. Generally our Daniel@0: approach has been to define defaults that favor convenience and good Daniel@0: looking output, and give the user options to override the defaults. Daniel@0: Daniel@0: ===Overview=== Daniel@0: Daniel@0: In the following, we will assume a ''standard'' version of Graphviz Daniel@0: with the full set of support libraries (fontconfig, gd, Cairo and Pango), Daniel@0: running on a desktop system or server with a standard installation of Daniel@0: font files. Daniel@0: Daniel@0: The graphviz layout engines (dot, neato, etc) create layouts with nodes Daniel@0: sized to enclose the text labels. This requires knowing the size of Daniel@0: the text blocks, which in turn requires knowing the metrics of the font Daniel@0: glyphs and their composition into words, taking into account wordspacing, Daniel@0: kerning, hinting, etc. So the overall process is: font specification, Daniel@0: then text layout, followed by Graphviz output (and final rendering on Daniel@0: the target display or device, which may or may not be by a Graphviz tool.) Daniel@0: Daniel@0: Daniel@0: A font is usually selected by family name ("fontname") and other properties Daniel@0: (see below: "Font selection"). Then fontconfig matches the request Daniel@0: to a system font. [Note: in older versions of Graphviz, fontname was Daniel@0: simply a file name. This required exact file name matching (with a little Daniel@0: bit of helpful name mangling under the hood, e.g. translating Times-Roman Daniel@0: to Times, or Helvetica to Arial on Windows systems (and yes we know Daniel@0: there is a difference). Under fontconfig, fontnames are family names, Daniel@0: which fontconfig matches to the closest font it finds. This always Daniel@0: "succeeds", but unfortunately produces surprising results if fontconfig's Daniel@0: idea of "close" doesn't match yours. This can happen when you specify Daniel@0: a custom (or just nonexistent) font, like Steve-North-Handwriting, Daniel@0: and fontconfig silently falls back to something safe like a typewriter Daniel@0: font.] Daniel@0: Daniel@0: Text layout is performed by pango, which accepts text and computes a Daniel@0: layout with metrics that determine node sizes. Daniel@0: Daniel@0: Though line drawing is provided by cairo for many output formats (and Daniel@0: likely more in the future), for raster output formats, font rendering Daniel@0: is passed though cairo to freetype. Freetype is also called if gd is Daniel@0: used for drawing. (gd can also be requested explicitly, e.g. dot -Tpng:gd, Daniel@0: or by default when Graphviz is built without cairo). Freetype provides Daniel@0: antialiasing, hinting, kerning, and other low-level font features. Daniel@0: Daniel@0: Font metrics are obtained from the fonts installed on the system running Daniel@0: Graphviz. Results are guaranteed when Graphviz outputs raster formats, Daniel@0: because freetype immediately renders the fonts into pixels. On the Daniel@0: other hand, with path-based formats like Postscript (-Tps) and SVG (-Tsvg), Daniel@0: final rendering may be done on a different platform altogether, with Daniel@0: different font files installed. Clearly, Your Milage May Vary. In the Daniel@0: case of Postscript, the driver in Graphviz passes the expected metrics Daniel@0: of the text block down to the renderer, and asks it to make a final stretch Daniel@0: (or squeeze) to force the text to fit the metrics that were in effect at Daniel@0: layout time. In Graphviz SVG, there is only a hope and a prayer that Daniel@0: the SVG rendering program's fonts match the ones fontconfig and freetype Daniel@0: used when Graphviz was run. (More about this later.) Daniel@0: Daniel@0: Default fonts and PostScript fonts. =================================== Daniel@0: Daniel@0: The default font in graphviz is, and always has been, Times-Roman. Daniel@0: Daniel@0: Graphviz has historically supported some ``standard'' Postscript Daniel@0: fonts, initially, Times-Roman, Helvetica, Courier and Symbol. Daniel@0: This list was later enlarged by Adobe to include 35 fonts, which are: Daniel@0: AvantGarde-Book AvantGarde-BookOblique AvantGarde-Demi Daniel@0: AvantGarde-DemiOblique Bookman-Demi Bookman-DemiItalic Daniel@0: Bookman-Light Bookman-LightItalic Courier Courier-Bold Daniel@0: Courier-BoldOblique Courier-Oblique Helvetica Daniel@0: Helvetica-Bold Helvetica-BoldOblique Helvetica-Narrow Daniel@0: Helvetica-Narrow-Bold Helvetica-Narrow-BoldOblique Daniel@0: Helvetica-Narrow-Oblique Helvetica-Oblique NewCenturySchlbk-Bold Daniel@0: NewCenturySchlbk-BoldItalic NewCenturySchlbk-Italic Daniel@0: NewCenturySchlbk-Roman Palatino-Bold Palatino-BoldItalic Daniel@0: Palatino-Italic Palatino-Roman Symbol Times-Bold Times-BoldItalic Daniel@0: Times-Italic Times-Roman ZapfChancery-MediumItalic ZapfDingbats Daniel@0: Daniel@0: Unfortunately, fontconfig doesn't recognize PostScript-style font Daniel@0: names directly, so Graphviz makes custom mappings from its list of Daniel@0: PostScipt names into fontconfig family names for use in all cairo Daniel@0: and gd based renderers. In -Tps output, these fonts are used without Daniel@0: name translation. Daniel@0: Daniel@0: Font selection. =============== Daniel@0: Daniel@0: The fontname attribute in .dot graphs is a fontconfig style specification. Daniel@0: From: http://www.fontconfig.org/fontconfig-user.html Daniel@0: Daniel@0: Fontconfig provides a textual representation for patterns that Daniel@0: the library can both accept and generate. The representation is Daniel@0: in three parts, first a family name list, second list of point sizes, Daniel@0: and finally a list of additional properties: Daniel@0: Daniel@0: -:=:=... Daniel@0: Daniel@0: Values in a list are separated with commas. The name needn't Daniel@0: include either a family or point size; they can be elided. In Daniel@0: addition, there are symbolic constants that simultaneously Daniel@0: indicate both a name and a value. Here are some examples: Daniel@0: Daniel@0: Name Meaning Daniel@0: ---------------------------------------------------------- Daniel@0: Times-12 12 point Times Roman Daniel@0: Times-12:bold 12 point Times Bold Daniel@0: Courier:italic Courier Italic in the default size Daniel@0: Monospace:matrix=1 .1 0 The users preferred monospace font Daniel@0: with artificial obliquing Daniel@0: Daniel@0: Graphviz currently has a seperate attribute for specififying fontsize. Daniel@0: Daniel@0: [ FIXME Daniel@0: We should allow the fontconfig style specification. "Times-20" does Daniel@0: not currently result in a 20pt font. Daniel@0: Daniel@0: This is probably because of special treatment of '-' for postscript Daniel@0: font names. Daniel@0: ] Daniel@0: Daniel@0: [ FIXME Daniel@0: We seem to have a bug with use of ':' in fontnames, probably because Daniel@0: of special treatment for filenames in Windows. Daniel@0: Daniel@0: In fontnames, use instead of ':' to separate values. Daniel@0: Daniel@0: -Nfontname="Courier:italic" doesn't produce an italic font in Daniel@0: graphviz-2.16.1, but: -Nfontname="Courier italic" works, but Daniel@0: -Nfontname="Monospace matrix=1 .1 0 1" doesn't. Daniel@0: ] Daniel@0: Daniel@0: Daniel@0: Font management with fontconfig. ================================ Daniel@0: Daniel@0: How can I tell what fonts are available? Daniel@0: $ fc-list Daniel@0: Daniel@0: How can I tell what fonts dot is using; Daniel@0: $ dot foo.dot -Tpng -o foo.png -v 2>&1 | grep font Daniel@0: Daniel@0: How can I add a custom font? Daniel@0: In the current version of Graphviz with fontconfig, Cairo and Daniel@0: Pango, this cannot be done by simply putting a file in the Daniel@0: current directory or setting the DOTFONTPATH path variable. Daniel@0: Your custom font must be explicitly installed by fontconfig tools. Daniel@0: Daniel@0: For a single font, e.g., foo.ttf: Daniel@0: $ mkdir -p ~/.fonts Daniel@0: $ cp foo.ttf ~/.fonts/ Daniel@0: Daniel@0: One can run fc-cache to speed up the use of fontconfig. Daniel@0: $ fc-cache Daniel@0: Daniel@0: For Windows users, one can go to the C:\windows\fonts Daniel@0: folder and use File -> Install New Font from the pull-down menus Daniel@0: to install the font. Daniel@0: Daniel@0: For a new font directory, e.g., /Library/Fonts, add a new element Daniel@0: Daniel@0: /Library/Fonts Daniel@0: Daniel@0: to a .conf file. Note that the file must have a correct xml structure Daniel@0: as specified by the fontconfig fonts.dtd. Possible choices for the Daniel@0: .conf file are local.conf in the same directory as the system-wide Daniel@0: fonts.conf file, or .fonts.conf in your home directory. Daniel@0: Daniel@0: How can I ... font? Daniel@0: See: http://www.fontconfig.org/fontconfig-user.html Daniel@0: Daniel@0: Can I specifiy a font by filename instead of by familyname? Daniel@0: Sorry, the answer is no. {The reason is that for this to Daniel@0: work, Graphviz has to intercept the font lookup before Daniel@0: fontconfig is called, and this can't be done when fonts Daniel@0: are being looked up by Pango.) Daniel@0: Daniel@0: Some versions of fontconfig appear to recognize pathnames and Daniel@0: attempt to use that, but this isn't always the case. Daniel@0: Daniel@0: How can I be sure that a specific font is selected? Daniel@0: Provide enough specification in the fontname, and test it Daniel@0: with fc-match to ensure that your desired font is selected. Daniel@0: (Note, this will not ensure that the same font is used in -Tps Daniel@0: or -Tsvg renderings where we rely on the fonts available on the Daniel@0: final printer or computer.) Daniel@0: Daniel@0: Note the downside, as mentioned previously, is that Graphviz cannot Daniel@0: do much to warn you when fontconfig didn't find a very Daniel@0: good match, because fontconfig just cheerfully falls back Daniel@0: to some standard font. It would be really nice if the Daniel@0: fontconfig developers could provide a metric reflecting the Daniel@0: quality of the font match in their API. Daniel@0: Daniel@0: What about SVG fonts? Daniel@0: Graphviz has a native SVG driver that we wrote (which is the Daniel@0: default), and cairo's SVG driver (which you get with -Tsvg:cairo). Daniel@0: Daniel@0: Graphviz' native SVG driver generates Windows compliant names Daniel@0: like "Times New Roman" or Arial by default. The names work in a Daniel@0: lot of situations (like Firefox running on Windows), but are Daniel@0: not guaranteed to be portable. If you set -Gfontnames=ps, Daniel@0: you get Postscript names like Times-Roman. If you set -Gfontnames=svg Daniel@0: you are guaranteed to get rock solid standards compliant SVG. Daniel@0: The SVG standard says that the legal generic font names Daniel@0: are Serif, Sans-Serif, and Monospace (plus Cursive and Daniel@0: Fantasy which we don't use in Graphviz). We generate those names. Daniel@0: The bad news is that various downstream renderers and editors Daniel@0: may resolve the generic font names differently, so it's not Daniel@0: quite clear how your SVG will look. Many W3C examples show Daniel@0: how to use CSS (Cascading Style Sheets) to get around this Daniel@0: problem by giving a list of font family names in order of Daniel@0: lookup precedence, but some downstream processors (like the Daniel@0: inkscape editor in Linux) don't implement CSS, so we're up a tree here. Daniel@0: Daniel@0: The cairo SVG driver solves this in an effective though brute Daniel@0: force way: it simply encodes embeds the needed fonts as lines and Daniel@0: curves in the target SVG. For small examples, -Tsvg:cairo is Daniel@0: about 10 times bigger than -Tsvg, but maybe it's worth it for Daniel@0: correctness. The other problem is that such SVG is much much Daniel@0: slower to render, no doubt because it bypasses any system Daniel@0: font rendering services, and does it the old fashioned way. Daniel@0: Daniel@0: What about Postscript fonts? Daniel@0: Daniel@0: say something here. What about non-ASCII like Latin1. Daniel@0: what about loading your own fonts via -L like in the old Daniel@0: days with the weird outline font example. Daniel@0: Daniel@0: ==="What if" issues for nonstandard Graphviz builds=== Daniel@0: The following only apply if you build your own version of Graphviz Daniel@0: by configuring and compiling the source code to build your own Daniel@0: custom executable. If you don't know what this means, it Daniel@0: definitely does not mean you. Daniel@0: Daniel@0: No freetype. ============ Daniel@0: Daniel@0: When graphviz is built on systems without freetype, then only the gd Daniel@0: renderer will be available for bitmap outputs, and the only available Daniel@0: fonts are a small set of builtin bitmap fonts. The poor quality of Daniel@0: these fonts will be evident, also, "dot ... -v 2>&1 | grep font" will Daniel@0: say that the font is "". This may actually be desirable Daniel@0: for installing minimal graphviz programs on a server where fonts Daniel@0: may not even be installed. Daniel@0: Daniel@0: Daniel@0: No fontconfig. ============== Daniel@0: Daniel@0: If graphviz is built on systems without fontconfig (e.g. Redhat-7) then Daniel@0: the fontname attribute will be interpreted as a font file name. The Daniel@0: system directories will be searched for this, or the directories can Daniel@0: be specified with the GDFONTPATH environment variable (or DOTFONTPATH Daniel@0: for historical reasons). Graphviz will use gd and freetype to obtain Daniel@0: metrics and render text. No pango/cairo renderers will be available Daniel@0: without fontconfig support. Daniel@0: Daniel@0: Daniel@0: Disabling fontconfig. ===================== Daniel@0: Daniel@0: Pango/cairo depends on fontconfig, so to disable fontconfig you also have Daniel@0: to disable pango/cairo. The easiest way to do this temporarily is to Daniel@0: edit /usr/lib/graphviz/config and remove the entire "libpango" block. Daniel@0: [Note that any changes to this file will be lost the next time graphviz Daniel@0: is updated, or "dot -c" is run with installer priviledges.] Daniel@0: Daniel@0: With pango disabled, graphviz will use gd which, even if it was built with Daniel@0: fontconfig support, will still allow fontnames to be given as filenames. Daniel@0: Daniel@0: You can also disable cairopango at build time with configure script options. Daniel@0: Daniel@0: Daniel@0: No gd. ===== Daniel@0: Daniel@0: Cairopango works without gd. We are moving graphviz to the pango/cairo Daniel@0: libraries, but gd still offers some features that are hard to replace, Daniel@0: such as JPEGs, GIFs and paletted color bitmap outputs. However, font support Daniel@0: is fully functional without gd so long as pango, cairo, fontconfig, Daniel@0: freetype are available. Daniel@0: Daniel@0: No pango/cairo. =============== Daniel@0: Daniel@0: Without pango/cairo, some of the key renderers are only available Daniel@0: with gd, which produces lower quality (but smaller) output. Daniel@0: Daniel@0: Looking forward, we expect to depend more on pango for things like: Daniel@0: line wrapping, multiple fonts per label, bidirectional text and Daniel@0: other internationalization features. Daniel@0: Daniel@0: No gd and no cairopango ===== Daniel@0: This is basically the original Graphviz without any external fonts. Daniel@0: It cannot render any raster formats, so it's mainly good for Postscript. Daniel@0: It relies on a few internal font tables