sammycage / lunasvg

SVG rendering and manipulation library in C++
MIT License
899 stars 125 forks source link

Possible issue with non-standard font #195

Open Randalphwa opened 5 days ago

Randalphwa commented 5 days ago

The SVG file below includes a text element with the font:

 style="font-family:'AmadeoStd', 'Amadeo Std';font-size:11px;"

The screen capture is of a text control label using the same font with the lunasvg rendering underneath. So even though the font is installed on my system (Windows 11) and works for the text control, it is not being rendered by lunasvg using that font. Not sure if that's by design or lunasvg doesn't support all fonts available on the OS/User's machine?

hello

GitHub doesn't have this font, and at least on my firefox it doesn't render at all, so here is the XML code:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
    <g transform="matrix(4.88894,5.28256,-4.24298,3.92683,78.4066,-42.6755)">
        <g transform="matrix(11,0,0,11,18.5165,17.5)">
        </g>
        <text x="0.894px" y="17.5px" style="font-family:'AmadeoStd', 'Amadeo Std';font-size:11px;">Hel<tspan x="12.422px 15.238px " y="17.5px 17.5px ">lo</tspan></text>
    </g>
    <g id="outer" transform="matrix(4.26667,0,0,4.26667,0,0)">
        <rect x="0" y="0" width="30" height="30" style="fill:none;"/>
    </g>
</svg>

Hello

KeyWorksRW commented 5 days ago

Just checked, and the SVG renders correctly in this issue in my Edge browser. I'm assuming it will not render correctly on any system without the AmadeoStd installed -- I just assumed it would be rendered correctly by lunasvg if the font was available.

sammycage commented 4 days ago

Thanks for sharing the details! Currently, lunasvg doesn’t support using fonts installed on the user’s system directly, except for a few default fonts set during setup. This may be why the text isn’t rendering as expected compared to your text control.

However, you can add custom fonts to lunasvg by using the lunasvg_add_font_face_from_file function. For example:

lunasvg_add_font_face_from_file("AmadeoStd", false, false, "/path/to/AmadeoStd.ttf");

This instructs lunasvg to use the specified font file for rendering text with the font family in your SVG, ensuring the correct font is applied.

Randalphwa commented 4 days ago

If I'm reading the code correctly, for Windows only Arial and Times are available and only then if Windows is installed on the C: drive. Text written in Arial would appear correctly on Windows, and differently on Unix (which uses DejaVuSans). So if the user wants to be certain the text is rendered the same on all platforms, they should include the font and load it into any Document that uses it before rendering the SVG. Is that essentially correct?

If I'm understanding correctly, for an SVG file rendering of a UI element that contains text, such as a drop down menu, then the dev should ideally read the UI font and supply that to the document. E.g., for Windows, that would mean locating the fonts directory, and calling lunasvg_add_font_face_from_file to load the Segoeui.tff file. That way the SVG rendering of the menu would match the UI of the OS.

sammycage commented 4 days ago

Great points! Yes, you’re absolutely correct.

Randalphwa commented 4 days ago

Any thoughts/plans about supporting font-face? That would allow embedding the font into the svg file:

    <style>
        @font-face {
                font-family: 'MyFontFamily';
                font-style: normal;
                font-weight: 400;
                src: local('MyFont'), local('MyFont'),
                url(data:font/myfont;base64,BASE_64_STRING_GOES_HERE) format('myfont');
        }
    </style>

I haven't actually tried doing this in an actual SVG file rendered with browser and/or Affinity Designer, but in theory it would prevent using the wrong font.

Just to be clear, I'm only trying to predict potential questions/issues that might come up both for direct lunasvg clients, and indirect clients when I finish hooking up lunasvg to wxWidgets. Though if you supported this, I'd probably add support for converting a font to base64 and embedding it in wxUiEditor, which in turn compresses the entire svg file and embeds it into the program using it.

sammycage commented 3 days ago

Thank you for the suggestion! Currently, there aren't any plans to support @font-face within the SVG framework, but I might explore this possibility in the future. For now, lunasvg_add_font_face_from_file or lunasvg_add_font_face_from_data could be used to embed fonts.

Randalphwa commented 3 days ago

Looking through the ttf files on my system, embedding the font in the SVG file might not be all that practical. Most of my fonts would increase the svg file by 1 meg when embedded, with one that would increase it by 42 megs. It's not just the size that's the issue, but lunasvg has to parse over all of that data to find the end tag and that's going to affect performance. I've already got the code in place for wxUiEditor to embed binary files, so I'll just look into a way to hook that up to the SVG files that need specific fonts.

sammycage commented 3 days ago

Thank you for sharing your insights! If the font data is static or already resides in memory, you can embed it without any additional memory overhead by using lunasvg_add_font_face_from_data and setting destroy_func to nullptr, or by defining a destroy function to free the data if needed. For example:

lunasvg_add_font_face_from_data("MyFamily" /*family*/, false /*bold*/, false /*italic*/, data, data_length, nullptr /*destroy_func*/, nullptr /*closure*/);