d2 icon indicating copy to clipboard operation
d2 copied to clipboard

Bundled font rendering issues

Open Mihara opened this issue 6 months ago • 2 comments

I spent a few hours chasing this issue around.

  1. If your d2 diagram includes a Cyrillic label on a connection...
  2. And you render to SVG...
  3. And you display this on a system which does not have its own copy of SourceSansPro...

...then the resulting label will be rendered in a default font. In my specific case (an MS Edge WebView) this happened to be a Times New Roman, which was how I noticed.

The actual cause appears to be the fact that the bundled SourceSansPro-Italic.ttf does not contain an Italic version of Cyrillic glyphs. While some SVG renderers will in fact construct faux-Italic in this case, MS Edge evidently will not. Which suggests Chrome won't either, so this problem might not be as exotic as it may initially sound.

Forcing those labels to be non-italic makes the problem go away.

P.S. While the proper workaround would be to supply my own fonts, I happen to need to use D2 as a library, where the process is not well documented, and naive use of AddFontStyle is apparently not sufficient...

Mihara avatar Aug 11 '25 10:08 Mihara

Hmm I wonder what should be done in this case. To bundle all the non-latin glyphs would be too large. I suppose at the very least, the CLI should output a warning that there are glyphs not covered by the default fonts. What would you want d2 to do?

naive use of AddFontStyle is apparently not sufficient

What do you mean by this?

alixander avatar Aug 11 '25 12:08 alixander

To bundle all the non-latin glyphs would be too large.

Naturally. However, I would think that if the bundled, base non-bold non-italic font includes a glyph, it is not an unreasonable expectation to be able to use it as italic and bold as well.

Base font includes Cyrillic, it's the italic one that doesn't.

My suggestion is to either remove Cyrillic from the base font, or add Cyrillic into the Italic font, and in general make sure that all variations of the bundled fonts at least handle the exact same list of codepoints.

What do you mean by this?



	regular, _ := os.ReadFile("tools/diagram/Roboto-Regular.ttf")
	italic, _ := os.ReadFile("tools/diagram/Roboto-Italic.ttf")
	bold, _ := os.ReadFile("tools/diagram/Roboto-Bold.ttf")
	medium, _ := os.ReadFile("tools/diagram/Roboto-Medium.ttf")

	font, err := d2fonts.AddFontFamily("Roboto", regular, italic, bold, medium)
	if err != nil {
		fmt.Printf("error making font: %v\n", err)
		os.Exit(1)
	}
	renderOpts := &d2svg.RenderOpts{}
	compileOpts := &d2lib.CompileOptions{
		LayoutResolver: layoutResolver,
		Ruler:          ruler,
		FontFamily:     font,
	}

....

			diagram, _, err := d2lib.Compile(ctx, buf.String(), compileOpts, renderOpts)
			if err != nil {
				fmt.Printf("Error compiling diagram: %v\n", err)
				os.Exit(1)
			}
			out, err := d2svg.Render(diagram, renderOpts)
			if err != nil {
				fmt.Printf("Error rendering diagram: %v\n", err)
				os.Exit(1)
			}


Given four TTF files of Roboto font, I would expect it to work, but no cigar:

Error compiling diagram: ruler does not have entire font family Roboto loaded, is a style missing?
exit status 1

I haven't been able to figure out what exactly does it want from me just yet.

Mihara avatar Aug 11 '25 15:08 Mihara