exupero / saveSvgAsPng

Save SVGs as PNGs from the browser.
MIT License
1.09k stars 362 forks source link

embedded font issues #24

Closed tedwardmah closed 6 years ago

tedwardmah commented 9 years ago

The script is nicely pulling in all of my svg styles when generating the png, except for fonts embedded using @font-face { ... } . It looks like the saveSvgAsPng script should handle embedded fonts within the styles() function on lines 73-74, so I'm wondering if there's something I'm missing here. I'm using a truetype font in my @font-face declaration. Are there any known issues when using embedded fonts?

exupero commented 9 years ago

Font face issues have been reported in the past, and the code you pointed out was intended to fix the problem, but after some investigation, there's more to it than simply including @font-face directives in the embedded CSS.

It turns out custom font faces needs to be inlined similar to the way images are being inlined before being loaded into a canvas. I've added a failing test for custom fonts to the tests page to make sure the problem is fixed.

Until saveSvgAsPng automatically inlines custom fonts for you, you can work around the problem by manually inlining them. For instance, the tests page uses the custom font Stalemate:

@font-face {
  font-family: 'Stalemate';
  font-style: normal;
  font-weight: 400;
  src: url(stalemate.ttf) format('truetype');
}

To inline the font yourself, change the value of the src property to

src: url("data:font/ttf;charset=utf-8;base64,<data>");

where <data> is the base64-encoded contents of your fonts file.

Hopefully I'll figure out a fix for for this sometime this week.

tedwardmah commented 9 years ago

Eric, thanks for this workaround, I feel very fortunate to have come across your script and blog entry. I had been inlining the @font-face declarations but had not been directly encoding in base64, which I believe was the issue. Everything is working perfectly now.

arunkjn commented 9 years ago

FYI- This format worked for me for embedding fonts- src: url(data:application/x-font-woff;charset=utf-8;base64,) format('woff');

nsonnad commented 9 years ago

Hey @exupero do you have any guidance on how best to implement the font embedding? I've started trying some things for a project I'm working on but not sure my approach is very good.

I've been able to convert the fonts to base64 strings by doing XHR GET requests for them, then encoding the xhr.responseText. My plan is to then write some hairy regex to replace the src: url(...) entries with the encoded string.

Here's an initial attempt that doesn't appear to be working: https://github.com/nsonnad/saveSvgAsPng/blob/inline-fonts/saveSvgAsPng.js

Thanks!

exupero commented 9 years ago

So far I haven't had any better ideas on how to tackle inlining fonts than doing a regex replace, so if you can make it work, go for it.

I haven't looked very closely at your code yet, but when I took a stab at the problem a few months ago, I ran into trouble wrangling the requests to get font data with the requests to inline image data.

nsonnad commented 9 years ago

Thanks. The latest version of my code almost works. It succeeds in getting the fonts, processing them as base 64, and replacing the url() CSS. The in-browser test you added passes.

The outstanding issue appears to be that on PNG download, the fonts don't work the first time, but work thereafter. I've moved to just inlining the fonts with a preprocessor, but think I'm pretty close. Will try to get back to it in the near future but would be great if you could have a look as well.

exupero commented 9 years ago

Excellent! Go ahead and make a pull request. I'll see if I can sort out the download problem.

Thanks for your work!

nsonnad commented 9 years ago

PR is at #29 ^

austinclemens commented 7 years ago

I am encountering the problem described by nsonnad in his 5/11/2015 comment - fonts do not render on the first save out, but do on every consecutive save. After a lot of testing I have no idea what is causing this but it does seem to be related to size of the SVG element - data uris and existing embedded fonts seem to cause problems.

My SVG is pretty complex and has an embedded font in defs and a medium sized image embedded as a URI. I thought maybe it was that my SVG element had some stuff already defined in defs (bc savesvg creates a 2nd defs element in the clone) but in simple examples this only causes the problem intermittently. Here's a minimal working example of the problem: http://www.austinclemens.com/test/test.html

At least in Chrome, the text won't render the first time the button is pressed after refreshing or loading the page. I think this is clearly related to overall size of the SVG - I have a huge data URI in this example for the chrome logo - but it's confusing to me that it then works on the 2nd try. Nothing changes about the clone object or the defs objects created by savesvg.

exupero commented 6 years ago

@austinclemens Thanks for the bug report. I suspect this is related to font loading. Since it's tangential to the main problem, please open a new issue if it's still a problem.