Last week I made a quick test demo in JSFiddle of downloading an image of an SVG. This was more interesting than I had expected which I’ll explain below. I created this demo as a way to test this kind of functionality in isolation from a more complicated work project.
SVG’s are neat because they are resizable and highly customizable elements. It stands for Scalable Vector Graphics and according to Mozilla “SVG is essentially to graphics what HTML is to text.”
The most interesting part to me was serializing. Serialization might be something that is often misunderstood (or just poorly understood) by beginner and self-taught developers. Understanding it can help you more quickly work through problems like converting an SVG into an image for download.
In the demo I made I have a little SVG element that’s not really doing much, it’s not a great example of an SVG I guess, but it’s simple with only a nested SVG group element within which is a text element and an image element. To make my demo more in-line with my work project’s use case I use D3 in the demo to add a new SVG group element within which is a rectangle element I use as an overlay to track mouse events and a circle element I use for more fluff during mouse events. Just to be clear, D3 is not at all necessary to get what I have rendered on the DOM here. Vanilla JS should be perfectly cromulent. Un-relatedly, do you think ‘cromulent’ is derived from Crom, the ancient god of the great Hyborian Age? I like to assume so.
Here are the steps, conceptually, to convert a basic SVG into an image for download:
- Grab your SVG.
- Create new image, canvas, and anchor elements (to be used shortly).
- Create a new instance of the XMLSerializer so that we can serialize the SVG to a string.
- Add the resulting string to our heretofore untouched image element’s source attribute.
- Draw the image onto the heretofore untouched canvas element.
- Append the anchor to your DOM.
- Convert the canvas element into a data URL and assign it as the anchor’s href attribute. This is where the SVG string is converted to PNG in base64 encoding.
- Assign the download attribute to provide a file name and finally call click on it to initiate the download.
This works in Chrome. I have not tried it in other browsers yet.
You may have noticed that the image element in my SVG (the animated gif) was not saved in the downloaded PNG. I expected this behavior because although the gif loaded on our page, we serialized the SVG to a string which only has that gif as an href. At no point once we serialize the SVG can the gif be loaded in those other contexts. If this were something you needed then you would have to convert the gif first and then convert the SVG.