Skip to main content

How to download an inline SVG as jpg or png

For a customer i had to build a small drawing app where one of the features was download your drawing. The drawing was an inline SVG and it had to be downloaded as a jpg or png image. Pretty straight forward, right?

Here is what I ended up doing:

  1. Covert inline SVG to data URI
  2. Draw image on canvas
  3. Convert canvas to blob url
  4. Force download

Covert inline SVG to data URI

You can convert an inline SVG to a base64 encoded string with the btoa function which I first did.

   "data:image/svg+xml;base64," + window.btoa(<svg> ... </svg>);

But since SVG is just xml like html you don’t need to base64 encode it, you can just pass it and hereby save kilobytes:

   "data:image/svg+xml,<svg> ... </svg>";

For IE support you need to encode some parts of the SVG. The lazy way is just encoding the entire SVG with encodeURIComponent(), but if size matters you can follow Taylor Hunt’s post on how to optimize SVG’s in data URIs.

Draw image on canvas

With the data URI you can create an image and draw it on canvas when the image is loaded.

   var ctx = canvas.getContext("2d");
   var image = new Image();
   image.onload = function () {
      ctx.drawImage(image, dx, dy, dWidth, dHeight);
   }
   image.src = "data:image/svg+xml,%3Csvg/%3E ... %3C/svg%3E";

Help it seems like Firefox can’t draw the image on canvas

If you’re having issues in Firefox please check that your inline SVG has a width and height defined (not in styling but as attributes). Even though it works in all other browsers without they’re needed for Firefox (tested with v. 49.0.2). Lost some time here I’ll never get back!

Convert canvas to blob url

After the image has been drawn on the canvas we can convert it to a jpg or png image. You can either do it with canvas.toDataURL which gives you a base64 string or canvas.toBlob which gives you a blob. Again, you can save kilobytes by not going with the base64 string.

   image.onload = function () {
      ctx.drawImage(image, dx, dy, dWidth, dHeight);
   
      // toBlob(callback, mimeType, qualityArgument);
      canvas.toBlob(function (blob) {
         var newImg = document.createElement("img"),
         url = URL.createObjectURL(blob);
         newImg.onload = function () {
            URL.revokeObjectURL(url);
         };
         newImg.src = url;
      }, "image/jpeg", 0.8);

   }

Force download

Now we want to download the image. In modern browsers there is a download attribute for anchors which tells the browser that it should download the resource the anchor points to rather than navigate to it. We can force it by creating an anchor and trigger a click with a mouse event:

   var event = new MouseEvent('click', {
    'view': window,
    'bubbles': true,
    'cancelable': true
   });

   var a = document.createElement('a');
   a.setAttribute('download', 'image.jpg');
   a.setAttribute('href', url);
   a.setAttribute('target', '_blank');
   a.dispatchEvent(event);

The download attribute is however not supported in IE or Safari yet why I’m checking for support and if not opening the image in a new window instead.

Download attribute support:

   var a = document.createElement('a');
   var downloadAttrSupport = typeof a.download !== "undefined";

Open in new window:

   var opened = window.open();
   if (opened) {
      opened.document.write(svg);
      opened.document.close();
      opened.focus();
   }

For Edge you can force a download with the msSaveOrOpenBlob() method.

   // Edge
   if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
      navigator.msSaveOrOpenBlob(blob, filename);
   }

4 thoughts to “How to download an inline SVG as jpg or png”

  1. Hallo! Did you ever try it with IE?
    I use IE10 and I’m getting a Security Error (besause of Canvas CORS).

Leave a Reply

Your email address will not be published.