Skip to content

Instantly share code, notes, and snippets.

@mbostock mbostock/.block
Last active Aug 6, 2019

Embed
What would you like to do?
Save SVG as PNG
license: gpl-3.0

Say you have an SVG built dynamically on the client by D3. Now say you want to save it to a static PNG as a fallback for old browsers. There are lots of ways to do this using alternative renderers (such as Batik and PhantomJS), but what if you want your browser to do it, so that you the static PNG matches the dynamic SVG exactly, down to the subpixel, including transparency?

Here’s how.

1. Save as SVG.

Use the SVG Crowbar bookmarklet to save the SVG to a file. Call this file “fallback.svg”. Open the SVG in your browser to verify that it looks right.

SVG Crowbar helpfully inlines any stylesheets you may have on the page, but you might find you need to edit a few of the styles by hand to get things to look right. For example, the font-family “sans-serif” won’t work in an SVG image, even though it works when the SVG is built client-side; you’ll have to make the font name explicit, such as “Helvetica” or “Arial”.

2. Convert SVG to PNG.

Create and save the following HTML file as “fallback.html”:

<!DOCTYPE html>
<meta charset="utf-8">
<canvas width="640" height="3250"></canvas>
<script>

var canvas = document.querySelector("canvas"),
    context = canvas.getContext("2d");

var image = new Image;
image.src = "fallback.svg";
image.onload = function() {
  context.drawImage(image, 0, 0);

  var a = document.createElement("a");
  a.download = "fallback.png";
  a.href = canvas.toDataURL("image/png");
  a.click();
};

</script>

Now start a local webserver in the same directory as your fallback.html file. For example:

python -m SimpleHTTPServer 8008 &

Lastly, visit http://localhost:8008/fallback.html, and it will automatically download fallback.png! Hooray.

Note: if you are using Chrome or Safari, you’ll need to download Chrome Canary due to this recently-fixed WebKit bug.

@CTimmerman

This comment has been minimized.

Copy link

commented Oct 2, 2015

I just made a similar one: https://gist.github.com/CTimmerman/c0f371b30bc85c689fa1
Wouldn't it be better to use the image dimensions for the canvas and to assign the image src after the onload function?

@runemadsen

This comment has been minimized.

Copy link

commented Dec 3, 2015

FYI: I have created an online SVG converter using this code: http://runemadsen.com/svg-converter/

@math2001

This comment has been minimized.

Copy link

commented Feb 21, 2017

@runemadsen exactly what I was looking for 👍

@jimlynnjulian

This comment has been minimized.

Copy link

commented Feb 22, 2017

I'm running Win10Prox64 on my laptop with Apache2 server (httpd) installed and had no problems with the Chrome browser.

@TheDamianHdez

This comment has been minimized.

Copy link

commented Apr 17, 2017

Super useful. Thanks a lot!

@plasticarm

This comment has been minimized.

Copy link

commented Aug 3, 2017

Wonderful Magic.

@cmullaparthi

This comment has been minimized.

Copy link

commented May 12, 2018

Hi,

I'm trying to use the technique above with the latest Chrome. I've tried it on Ubuntu, Centos and OS X and I get the following error from chrome and the png is not produced. The web server logs show that it is downloading the HTML and the SVG file, but no PNG is produced. Any hints on how to troubleshoot this?

$ chrome --headless --remote-debugging-port=9222 --disable-gpu http://localhost:8008/fallback.html

[0512/152511.928496:ERROR:gpu_process_transport_factory.cc(1007)] Lost UI shared context.

DevTools listening on ws://127.0.0.1:9222/devtools/browser/8489b855-b30e-4775-a7f9-da19bd68d821
@Inchworm333

This comment has been minimized.

Copy link

commented Aug 6, 2019

Finally, I can properly render the svg to a png! Thank You!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.