Convert SVG to PNG using your browser


23 Sep 2017

Lots of web pages now rely on SVG instead of PNG or JPG images. SVG stands for Scalable Vector Graphics, an XML-based vector image format that scales well, unlike bitmap images (bitmaps become pixelated when up-sized). I recently wanted a quick way to convert a SVG to PNG, and discovered modern browsers (read: Chrome and Firefox) can do this with a simple bit of code.

If you are looking for a tool to edit and convert SVGs, look elsewhere. For example, try GIMP, Inkscape or LibreOffice Draw.

But if you are looking for a quick and dirty way to input SVG XML directly in your browser, and using your browser to then convert this to PNG, read on. I specifically didn't want to use on-line conversion services that required me to save the SVG as a file and upload the file, then download the result.

My intention is to do the conversion purely within the browser - nothing is sent to any server, not the SVG nor the PNG generated! You could run this code purely from a static HTML file on your computer with no internet connection.

SVG to PNG JavaScript

The core code from Ciro Costa, replying to a StackOverflow question Save inline SVG as JPEG/PNG/SVG". I then edited it to read the SVG from a textarea, added the ability to scale the image, added a sensible file name, based on the SVG "id", "name" or "aria-label" tags, and fixed the way the file is downloaded for Safari!

Without further ado, here's the code - a HTML page with no formatting (no CSS) or dependencies (no jQuery) :

<title>myByways SVG to PNG Converter</title>
<body bgcolor="#E6E6FA">
 <h1><a href="">myByways SVG to PNG Converter</a></h1>
 <textarea id="t" rows="8" cols="70"></textarea><br/><br/>
 <button id="l">Load SVG</button><br/><br/>
 <div id="d"></div><br/>
 Width: <input id="w" type="number" max="9999"></input>
 Height: <input id="h" type="number" max="9999"></input>
 <button id="s">Save SVG as PNG</button><br/><br/>
 <canvas id="c"></canvas>
/* SVG to PNG (c) 2017 CY Wong / */
var text = document.getElementById('t');
text.wrap = 'off';
var svg = null;
var width = document.getElementById('w');
var height = document.getElementById('h'); 
document.getElementById('l').addEventListener('click', function () {
  var div = document.getElementById('d');
  div.innerHTML= text.value;
  svg = div.querySelector('svg');
  width.value = svg.getBoundingClientRect().width;
  height.value = svg.getBoundingClientRect().height;
document.getElementById('s').addEventListener('click', function () {
  var canvas = document.getElementById('c');
  svg.setAttribute('width', width.value);
  svg.setAttribute('height', height.value);
  canvas.width = width.value;
  canvas.height = height.value;
  var data = new XMLSerializer().serializeToString(svg);
  var win = window.URL || window.webkitURL || window;
  var img = new Image();
  var blob = new Blob([data], { type: 'image/svg+xml' });
  var url = win.createObjectURL(blob);
  img.onload = function () {
    canvas.getContext('2d').drawImage(img, 0, 0);
    var uri = canvas.toDataURL('image/png').replace('image/png', 'octet/stream');
    var a = document.createElement('a');
    document.body.appendChild(a); = 'display: none';
    a.href = uri = ( || svg.svg.getAttribute('name') || svg.getAttribute('aria-label') || 'untitled') + '.png';;
  img.src = url;

On Retina Displays, the PNG that you see previewed and ultimately saved looks terrible compared to the SVG, because it's generated at the given resolution. Retina displays then have to scale this up, usually by a factor of x2. Try this on a non-retina display and the PNG looks identical to the original SVG. Or, if this bugs you, go implement drawImage() for High DPI canvas, which will basically generate a x2 image anyways!

In addition, it was a challenge to get the image to download on Safari. In Firefox, this would work a.dispatchEvent(new MouseEvent('click', { view:window, bubbles:false, cancelable:true })); but in Safari, I had to use document.body.appendChild(a);; document.body.removeChild(a); instead. Whatever.

Sample SVGs to Test the Code

You'll find it in action further on this page. To test it you can:

  1. Copy the SVG XML from the samples below.
  2. Paste into the text box, and click Load SVG.
  3. Preview it, change the width or height if required.
  4. Hit Save SVG as PNG to automatically save the generated PNG.

Here is the SVG XML for this icon from IBM's Carbon Design System, © IBM, Apache License 2.0

<svg width="24" height="24" viewBox="0 0 24 24" fill-rule="evenodd">
 <path d="M12 1.2l10.5 5.7L12 12.8 1.5 7.1 12 1.2zM12 0c-.2 0-.4.1-.6.2L.4 6.3c-.6.4-.6 1.2 0 1.5l11 6c. 0 .4-.1.6-.2l11-6.1c.6-.4.6-1.2 0-1.6l-11-6H12z"></path>
 <path d="M12.1 18.9c-.3 0-.5-.1-.8-.2L.7 12.8c-.5-.2-.7-.7-.7-1.1 0-.5.2-.9.7-1.2l.6-.4c.2-.2.5-. 0 .1 0 .2.2.3l10.6 5.9c. 0l10.5-6c.2-.1.2-.3.2-.3 0-.1 0-.2-.2-.3l-.6-.3c-.2-.1-.4-.4-.2-.7.1-.2.4-.3.7-.2l.5.3c. 1.2s-.2.9-.7 1.2l-10.5 6c-.2 0-.5.1-.7.1z"></path>
 <path d="M12.1 24c-.3 0-.5-.1-.8-.2L.7 17.9c-.5-.2-.7-.7-.7-1.2s.2-.9.7-1.2l.6-.4c.2-.2.5-. 0 .6-.2.8l-.6.4c-.2.1-.2.3-.2.3 0 .1 0 .2.2.3l10.6 5.9c. 0l10.5-6c.2-.1.2-.3.2-.3 0-.1 0-.2-.2-.3l-.6-.3c-.2-.1-.4-.4-.2-.7.1-.2.4-.3.7-.2l.5.3c. 1.2s-.2.9-.7 1.2l-10.5 6c-.2.1-.5.2-.7.2z"></path>

Here is another icon from HP's Grommet UI library for React.js © Hewlett Packard Enterprise Development LP, Creative Commons Attribution 4.0

<svg version="1.1" viewBox="0 0 24 24" width="24px" height="24px" role="img" class="grommetux-control-icon grommetux-control-icon-workshop grommetux-control-icon--huge grommetux-control-icon--responsive" aria-label="workshop">
 <path fill="none" stroke="#000" stroke-width="2" d="M19,7 C19,7 14,14 6.5,14 C4.5,14 1,15 1,19 L1,23 L12,23 L12,19 C12,16.5 15,18 19,11 L17.5,9.5 M3,5 L3,2 L23,2 L23,16 L20,16 M11,1 L15,1 L15,3 L11,3 L11,1 Z M6.5,14 C8.43299662,14 10,12.4329966 10,10.5 C10,8.56700338 8.43299662,7 6.5,7 C4.56700338,7 3,8.56700338 3,10.5 C3,12.4329966 4.56700338,14 6.5,14 Z"></path>

myByways SVG to PNG Converter

Width: Height: