Plotly.js: Missing fonts in PNG exports

Created on 30 May 2020  路  19Comments  路  Source: plotly/plotly.js

Here's an example of a plotly chart with a custom font included:

https://codepen.io/etpinard/pen/jAzVVL

When clicking the "download plot as PNG" option, the downloaded file appears to have a different font than the chart.

Is there something I need to do to make sure that the font is included with the exported image?

bug

All 19 comments

Hmm... not sure if this is a bug.
@antoinerg FYI - codepen somehow displays the custom font but it is not used in the PNG export.
However if I past the JS code in the dashboard, the custom font does not show up in the browser.

Certainly looks like a bug to me - thanks for the report @cjacksudo!

Did a little poking around - if you ask for an svg download (using config option toImageButtonOptions: {format: 'svg'}) the font is included correctly, so the problem is at the svg -> raster step.

My guess is the problem is with this canvas:

https://github.com/plotly/plotly.js/blob/5b8b1db1386b82db747cbad239fed754e624a18f/src/snapshot/toimage.js#L44

not being appended to the DOM, so it doesn't have access to fonts loaded in the document. Possibly just adding it to the DOM (but putting it offscreen somewhere) would fix the issue?

Has there been any progress on this? Or is there a temporary work-around?

In my case the font isn't even included in svg downloads.

I just tried the following Codepen and to my surprise, the PNG export does contain the correct font on Chromium Version 85.0.4183.83 (Developer Build) (64-bit) on Linux. I could however reproduce the issue on Firefox.

I forked the original Codepen provided in this issue (https://github.com/plotly/plotly.js/issues/4885#issue-627594588) and replaced 'Oswald' by Oswald and fonts are now properly rendered even in Firefox: https://codepen.io/antoinerg/pen/vYKbGKm

In summary, it seems like Firefox and some other browsers choke on single quotes. The library performs some manipulation of quotes in https://github.com/plotly/plotly.js/blob/master/src/snapshot/tosvg.js#L114. I suspect the fix will be in this file.

Has there been any progress on this? Or is there a temporary work-around?

In my case the font isn't even included in svg downloads.

@LTribelhorn are you using single quotes? Can you try removing them? See https://github.com/plotly/plotly.js/issues/4885#issuecomment-726852154 for an explanation.

@antoinerg for what it's worth, I tried your codepen without any luck - the behavior is the same, and the font is not included in the downloaded png.

I'm on chrome 86.0.4240.198

@antoinerg for what it's worth, I tried your codepen without any luck - the behavior is the same, and the font is not included in the downloaded png.

I'm on chrome 86.0.4240.198

Thanks @cjacksudo for the quick reply! What is your operating system?

Does this one also fail for you: https://codepen.io/antoinerg/pen/pobGgQZ ?

I'm on macOS (10.15.6).

Yeah, I'm seeing the same thing with https://codepen.io/antoinerg/pen/pobGgQZ

I updated my Codepen to use a dev build of plotly.js which contains a fix. Can someone please confirm it is indeed working on their OS/browser?

cc @archmoj @cjacksudo

I updated my Codepen to use a dev build of plotly.js which contains a fix. Can someone please confirm it is indeed working on their OS/browser?

cc @archmoj @cjacksudo

Not working on my machine.
@antoinerg
Wondering if one should open the downloaded image in the browser?

Not working on my machine.

What's your browser and OS @archmoj ? It works for me both in FF and Chromium on Linux... :confused:

Wondering if one should open the downloaded image in the browser?

Since they are PNG, it shouldn't matter what you use to open them!

That new codepen still fails for me (Chrome 86 or any other browser, Mac OS 11.0.1)

@antoinerg
Wondering if one should open the downloaded image in the browser?

Nevermind. It is a png so it should not matter.

Still fails for me as well

It turns out my Codepen was using fonts already installed on my workstation so please disregard my comments above :man_facepalming:

The bad news is that we rely on <img> to turn our SVG into an image and according to https://stackoverflow.com/a/42405731

For security reasons, <img> inner documents can not make any external requests.
This means that you'll have to embed all your external resources as dataURIs inside your svg markup itself, before loading it to the <img> element.

Therefore, to support custom fonts in SVG/PNG exports via CSS (ultimately the @font-face rule), we would need to inject the style in the SVG itself inside <defs>. Example:

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
    <defs>
        <style>
            @import url("https://fonts.googleapis.com/css?family=Roboto:400,400i,700,700i");
        </style>
    </defs>
    <style><![CDATA[svg text{stroke:none}]]></style>
    <text x="20" y="50" font-family="Roboto">Roboto</text>
</svg>

@alexcjohnson is this something we want to support (ie. allow users to specify fonts to embed via some attribute)?

It would be a bit unfortunate if we needed to require users to explicitly specify these, just to make the downloaded image match what's already in their graph; I was hoping we'd be able to just read out the@font-face rules that were active in the document, and add them automatically. And it seems like we can do that for locally-defined rules (by hunting through document.styleSheets) but it's forbidden for imported stylesheets... we can see the URLs and could just @import all of them?

That sounds like a pain though, and might cause problems in some contexts, so yeah perhaps in the short term we could just accept an option to specify these fonts explicitly.

Has there been any progress on this? Or is there a temporary work-around?
In my case the font isn't even included in svg downloads.

@LTribelhorn are you using single quotes? Can you try removing them? See #4885 (comment) for an explanation.

@antoinerg Sorry for the late response and thank you very much for your effort.
I am using the R-Implementation of plotly so the usecase is different but I thought the problem might be connected. If you don't think so I could open a new issue in the R-Repository.

For context:
I am using plotly in a Shiny-app and I define the fonts as specified in the documentation with font_p <- list(family = "Roboto", size = 14) and import the font in the UI with tags$head(tags$style(HTML("@import url('//fonts.googleapis.com/css2?family=Roboto:wght@300;700&display=swap');")))

@antoinerg if the issue is downloading the font, shouldn't this pen work: https://codepen.io/cjacksudo/pen/yLazRRE?

I looked through the SO answer you linked (https://stackoverflow.com/a/42405731) and it seems like the setting the font-face rule to reference a data string should solve it, but it doesn't appear to...

EDIT: I see it - confirmed that adding the rule inside of the svg fixes it.

Was this page helpful?
0 / 5 - 0 ratings