The difference is subtile, but there are extra spaces between main and the opening parenthesis, as well as between Fn() and the comma, and between usize and the closing parenthesis.
OS Version
Archlinux, up-to-date
Graphviz Version
$ dot -Vdot - graphviz version 2.44.1
Additional info
I discussed it on the forum and the bug was reproducible.
Edited
Designs
Child items ...
Show closed items
Linked items 0
Link issues together to show that they're related or that one is blocking others.
Learn more.
Activity
Sort or filter
Newest first
Oldest first
Show all activity
Show comments only
Show history only
Robin Moussuchanged the descriptionCompare with previous version
Using dot -Tsvg:cairo totally solved the issue. I don't see how it could be documented better however, so feel free to close the issue (I just wants to be sure that the deliverability difficulty was known by at least someone ).
Note: there are no reference to "cairo" in the man-page.
Note: there are no reference to "cairo" in the man-page.
graphviz.gitlab.io!722 (merged) adds some website words about our frequent flyer, -Tsvg:cairo. If you have any other suggestions for the website or man pages, please feel free to post MRs.
To maybe restate the problem that you already understand: the graph layout
engine needs the font metrics at layout time to size the nodes. If font
config can't find the font it will default to Times, which may not match
the metrics of the ultimate SVG font.
One solution might be to train fontconfig on the layout host about more of
the SVG fonts that it may encounter.
Q. Are SVG fonts standardized across all OS that might be rendering?
The other solution is to use svg:cairo to render text as bit maps at the
same time as it generates the layout, and then embeds the bitmaps in the
SVG.
I wonder if this is just fonts or if we are accidentally emitting extra
whitespace. The extra spacing looks possibly more than what a font being
present or not would account for
I'm running into this same issue, but I can't use the workaround because the addition of cairo also breaks the insertion of clickable URLs into the SVG. For now I'm going to avoid using HTML-like labels to keep clickable links.
I can't repro this. -Tsvg and -Tsvg:cairo give different output, but both of them display correctly for me (Fedora Linux 36). @magjac, on the forum thread you said you can repro. Is this then OS-specific?
To clarify, generally someone is only going to see this mismatch when graphviz -Tsvg:core output is generated on one computer, then viewed on another computer that has different fonts.
It could occur even when viewing the generated SVG on the same computer, if the renderer does not access the same fonts as Graphviz, or interprets font names differently than graphviz. (By graphviz, we include the underlying libraries like cairopango and freetype or quartz that perform this for graphviz.)
Two minor notes:
If you look at the specs, basic SVG isn't intended to nail down text layout.
Cairopango SVG output gets around this by encoding font glyphs as SVG shapes, but it's a lot of complication. The graphviz core SVG generator (essentially a bunch of printfs that we wrote ourselves) isn't capable of that.
The problem does not occur when viewing the file. It occurs when generating it as you can see above. Running in verbose mode shows this difference on stdout when grepping for "font":
Not in the latest difference I reported. Cairo is not involved there. The core renderer is used in both cases. The only difference is that in one case I use the dot program and in the other a small tests case using Graphviz as a library. They should give the same result, but don't. My guess is that dot does something that causes the DejaVu font to be found, while my test program doesn't and falls back to "internal hard-coded", whatever that is.
The dot version looks bad with eog but correct with Firefox while the test program version looks good with eog and bad with Firefox, but instead of extra space, there's too little space:
So when I said that the problem does not occur when viewing the file, I was not entirely correct. Of course you don't experience the problem until you view the file, but here we have two ways to render the graph that gives different SVG that views good or bad depending on which font the program that views it uses.
In my case, eog does not seem to find the DejaVu font and therefore shows the SVG generated using the DejaVu font badly, while showing the one with the "internal hard-coded" fine. Firefox does find the DejaVu font and therefore does the opposite.
I ran into a version of this with the Graphviz Visual Editor.
It can be somewhat tricky to reproduce, because...
It does depend on the font selected
And the font used (not always the same thing)
BUT not in the ways you'd think
What I mean by that is, it's often the case that Graphviz is using the same font for layout that's embedded in the SVG, but it still places text in positions that cause problems with other SVG renderers.
For example, using the following graph definition:
graph G { rankdir="TB"; n [fontname="Times-Roman" label=<Wow, <i>some</i> other <u>styled</u> text>]; m [fontname="DejaVu Serif" label=<Wow, <i>some</i> other <u>styled</u> text>]; o [fontname="Times" label=<Wow, <i>some</i> other <u>styled</u> text>]; p [fontname="DejaVu Serif" label=<Wow, <i>some</i> other <u>styled</u> text>]; n -- m -- o -- p;}
running it through dot -v -Tsvg reveals that on my system, it selects "DejaVu Serif" for the "Times-Roman" font; as a result, unsurprisingly, the x coordinates of all of the text boxes for the first, second, and fourth nodes are exactly identical; only node 'o' is laid out differently (having named "Times" as the font, which selects "Nimbus Roman" on my system):
But when rendered by most SVG renderers, with DejaVu Serif being an available font, the spacing in the second node (the one that actually uses "DejaVu Serif" in the SVG <text> tags) will be incorrect. Here's an only-slightly-modified version of the SVG output from that operation:
From <text x= y=>...</text><text x= y=>...</text> to <text x= y=><tspan>...</tspan></text>
Modified how? Well, I hand-edited the SVG code for the fourth node (that's why I created two identical ones), changing it from this:
That's why, no matter what your renderer shows for the first two nodes, the text in the fourth one should all be spaced properly according to the metrics of whatever font is being used to render it.
Here's a wrapped version of the source for readability, though in the code it needs to be all one line precisely because it's using white-space:pre to preserve the space characters:
There's just a single <text> tag that sets the x/y coordinates of the start of the text line, and applies the CSS white-space:pre property to the enclosed text. Then all of the text inside it is styled using <tspan> tags that don't force positioning, they just allow the text to be laid out according to the font metrics.
The designers of SVG understood that font replacement would make sizing text unreliable, so they designed the <tspan> tag to make style adjustments without resetting the text flow, just like in HTML. Graphviz's SVG renderers never use it, only <text> tags with explicit x and y positions, which is why text so frequently lays out incorrectly.
Internal drawing routines
dot's own -Tpng mode never has these issues, but that's because it cheats: the default PNG renderer is usually -Tpng:cairo:cairo, which just like -Tsvg:cairo:cairo will position and draw each individual glyph graphically based on whatever weird notion of font metrics its internal font-layout system uses. That's fine if you're generating a PNG, but as @davidvandebunte discovered, it's no good for SVG because your text isn't text anymore, which means things like hyperlinks (as well as text-selection, copy-paste, etc.) no longer work.
The SVG source of one of those nodes produced by dot -Tsvg:cairo:cairo, for example, is:
(To keep text centered in a node, and handle a wider range of font replacements gracefully, using <text text-anchor="middle" x="$x_center_of_node"> might also be a smarter layout choice than setting an explicit x coordinate for the left edge of the text.)
If I can try to summarize: it's commonly recognized when generating and rendering SVG that the generator and the renderer may not have the same fonts, and using <tspan> to change text rendering options within a given text flow allows the resulting errors to accumulate and not interrupt the text layout.
A difficulty is the graphviz driver is not structured to use that feature. It breaks a text label into text spans and then renders each indepedently, as you noticed.
Not sure how much effort it would take to rework the driver to handle generate SVG as proposed above.
Not sure I sympathize with the tone of mild indignation. The behavior of the native SVG generator can be seen in the code for SVG text generation.
The original code generator was the native Postscript generator. @ellson made a huge leap forward by integrating libgd to generate gif, png and jpeg. This made graphviz usable in web applications. It's just pixels of course, there is no text structure. We used fontconfig to bind font files and freetype to render them. It's not hard to see why cairo decided to bite the bullet and render its own glyphs - even using there's no way to be really sure how the text will render, otherwise.
Maybe we should have thought more about <tspan> and we talked with Adobe around the time of SVG 1.1 in 2003(?) We didn't understand the issues very well but could realize that text was problematic and they did not want to recreate HTML but were on a slippery slope there. (OpenGL isn't good at text, either.) We were just viewing SVGs in Inkscape or Adobe Illustrator; there was little interest from our user community back then.
I don't know if this will help, but isn't there a parameter to adjust the
padding around the text bounding box? That might give more room for
mismatched fonts.
If I can try to summarize: it's commonly recognized when generating and
rendering SVG that the generator and the renderer may not have the same
fonts, and using to change text rendering options within a given text flow
allows the resulting errors to accumulate and not interrupt the text layout.
A difficulty is the graphviz driver is not structured to use that feature.
It breaks a text label into text spans and then renders each indepedently,
as you noticed.
Not sure how much effort it would take to rework the driver to handle
generate SVG as proposed above.
The original code generator was the native Postscript generator. @ellsonhttps://gitlab.com/ellson made a huge leap forward by integrating libgd
to generate gif, png and jpeg. This made graphviz usable in web
applications. It's just pixels of course, there is no text structure. We
used fontconfig to bind font files and freetype to render them. It's not
hard to see why cairo decided to bite the bullet and render its own glyphs
even using there's no way to be really sure how the text will render,
otherwise.
Maybe we should have thought more about and we talked with Adobe around
the time of SVG 1.1 in 2003(?) We didn't understand the issues very well
but could realize that text was problematic and they did not want to
recreate HTML but were on a slippery slope there. (OpenGL isn't good at
text, either.)
Wait, can this proposal be done in the SVG driver without any API changes? Because the driver can easily find the intended (computed) midpoint of the text, which is all that is needed.
I understand the problem of not knowing the metrics of the fonts in the
final rendering, but I m not sure if I'm understanding the specific
problem here?
Textspans can be multiline, with lines separated by \l \n or \r. \n will
give ragged left and right edge text blocks. Would that help with
centering?
Or perhaps we should ask Adobe for an interface with a box and a text scan,
and have the final renderer scale to fit.
Wait, can this proposal be done in the SVG driver without any API changes?
Because the driver can easily find the intended (computed) midpoint of the
text, which is all that is needed.
This file is similar to Steve Roush's, I have only added a table (because I was having issues with tables). I have converted the source file to SVG and then used ImageMagick to convert the SVG to PNG (this appeared to be a reliable way to convert it into a portable format that can be observed by you that will preserve the breakage). I did the tests twice, once without having msttcorefonts installed and once with them installed.
It's informative to manually inspect the svg files uploaded above. What you see is that only some of the custom fonts in the graphviz file were resolved to expected fonts. For example, for graphviz the node n14 with font name calibri generates SVG font-family="calibri" and the resulting PNG looks ok. But for a lot of custom graphviz fonts like Palatino-Roman resolve to just the fontconfig backup font-family="Times,serif" so there's no assurance that Graphviz and Imagemagick will find the same thing.
Although the generated SVG files differ, in SVG you get the same fonts, as shown by this:
Instead of using Imagemagick, dot -v -Tpng lists font bindings and shows the internal rendering it is working from.
As explained elsewhere, there's no guarantee that dot -Tsvg gives results that are consistent across environments or even different programs on the same computer.
Does anyone have an actionable suggestion for resolving this issue? There’s a lot of ink spilled above, and while it all seems constructive it also doesn’t seem to be converging on a solution.
OTOH I am a ignorant fool who knows only just enough about fonts to be dangerous, but asking for a font the generating machine and/or the target machine do not know surely is never going to end well? Best case scenario, you have an educated guess that includes subjective whitespace problems like the above. To me, this issue seems to be trying to address an inherently unsolvable problem. As Stephen says:
there's no guarantee that dot -Tsvg gives results that are consistent across environments or even different programs on the same computer.
In this post it's claimed that post processing SVG with a tool called nano can solve this problem. But it's not open source or even a tool you can install - it's a website. Its name conflicts with a popular editor! (brew info nano is a different program. Confusing.)
This article by the nano people (Siemens?) under "Using fonts with Object tags" proposes a way to use CSS like styling with SVG to @impor web fonts. What if graphviz recognized Google API font namesand generated those elements.
This might be more feasible than trying to find the font files that were loaded by pango and generating an embedding a BASE64 representation, like the pangocairo driver does, and more in the spirit of the native SVG driver.
There does seem to be a way to improve the svg font selection problem.
It is not a "one-size-fits-all" fix, but still a significant improvement for many users.
This proposal is to add the @face-font svg feature (https://www.w3.org/TR/SVG11/fonts.html#FontFaceElement) as an option to Graphviz svg output.
This would allow the end-user to use the same font when displaying an svg file as was used to define the graph.
@face-font provides two alternatives:
embed the required font file(s) in the svg file
provide a link in the svg file to the required font file(s), locally or remotely
Each alternative has advantages and disadvantages
embedding font file(s):
font files are large - 50K to 5M bytes, each. a "small" svg file would become much larger with embedding
easy to add @font-face embedding to Graphviz (files must be local to the Graphviz system (Fontconfig will not work with remote font files)
compression and/or font file "subsetting" can reduce font file size, but requires extra tools
works for all end-users: local, web-based, and remote non-web-based
link to font-file
for local users (svg output generated & used on same computer) link can be to the local font file
fontconfig does not seem to be able to use remote font-files (webfonts). These font files would have to be downloaded for fontconfig
web-based users can be linked to font files provided by the web server
some font files are currently provided by (web-based) font servers (free or fee)
remote non-web-based end-users have no access linked font file(s)
Interestingly, correct @font-face code (linking or embedding) can be successfully inserted into current Graphviz svg output. Not a trivial task, but doable.
To determine the fonts and font files used for the sizing step for an input graph
add the -v -Gfontnames=ps options to the command line
grep the stderr output for the term 'fontname:' or "resolved to'
this provides the used font name & font file name
fontnames=ps results in correct (or nearly correct) font names in the generated svg (fontnames default value produces SVG fontnames that can't be easily associated with the font used to generate the svg)
then text processing the svgfile
add the @font-face lines (with links or embedded font files)
modify all the '<text' lines
to adjust the font name
to add font-style, font-stretch, and font-weight terms as needed
I have a bash/gawk script that does all this, but incorporating it into plugin/core/gvrender_core_svg.c is a much better idea
There does seem to be a way to improve the svg font selection problem. It
is not a "one-size-fits-all" fix, but still a significant improvement for
many users.
This proposal is to add the @face-font svg feature (
https://www.w3.org/TR/SVG11/fonts.html#FontFaceElement) as an option to
Graphviz svg output. This would allow the end-user to use the same font
when displaying an svg file as was used to define the graph. @face-font
provides two alternatives:
embed the required font file(s) in the svg file
provide a link in the svg file to the required font file(s), locally
or remotely
Each alternative has advantages and disadvantages
embedding font file(s):
font files are large - 50K to 5M bytes, each. a "small" svg file
would become much larger with embedding
easy to add @font-face embedding to Graphviz (files must be local
to the Graphviz system (Fontconfig will not work with remote font files)
compression and/or font file "subsetting" can reduce font file
size, but requires extra tools
works for all end-users: local, web-based, and remote
non-web-based
link to font-file
for local users (svg output generated & used on same computer) link
can be to the local font file
fontconfig does not seem to be able to use remote font-files
(webfonts). These font files would have to be downloaded for fontconfig
web-based users can be linked to font files provided by the web
server
some font files are currently provided by (web-based) font
servers (free or fee)
remote non-web-based end-users have no access linked font file(s)
Interestingly, correct @font-face code (linking or embedding) can be
successfully inserted into current Graphviz svg output. Not a trivial task,
but doable.
To determine the fonts and font files used for the sizing step for
an input graph
add the -v -Gfontnames=ps options to the command line
grep the stderr output for the term 'fontname:' or "resolved to'
this provides the used font name & font file name
fontnames=ps results in correct (or nearly correct) font names in
the generated svg (fontnames default value produces SVG fontnames that
can't be easily associated with the font used to generate the svg)
then text processing the svgfile
add the @font-face lines (with links or embedded font files)
modify all the '<text' lines
to adjust the font name
to add font-style, font-stretch, and font-weight terms as
needed
I have a bash/gawk script that does all this, but incorporating it into
plugin/core/gvrender_core_svg.c is a much better idea
Searched for a library to generate @font-face rules, but found only the npm font-face-generator package. Couldn't find a library that works with fontconfig.
It seems like textfont_t would be the appropriate place to store a path reference if it is available. Although all this code is quite old, font encapsulation came late (probably around the time when HTML labels were added) so more global cleanup might be needed to get this to work nicely. I think we previously observed that pango/freetype does not provide an API to access font face content, so that would hinder generating inline fonts. Also, I think there's a problem of font encodings and translating between them, which seems to be getting well outside the intended scope of Graphviz itself. (To me, this discussion reveals how much a text based tool that does final text layout is an outlier in the ecosystems we use.)
Just noticed that the "Pacifico" example (above) does not display correctly on this page.
It will display correctly if you "open image in new tab" (really it seems to download the svg file) and then open the downloaded svg file. Cripes.
Also, implement the suggestion from 2020 to embedded an SVG comment that explains where to find more information about this issue to help more inquisitive people.