While SVG is supported in all modern browsers, I'm often asked for help in converting JET's SVG visualizations to other image formats to support use cases like emailable dashboards. We can do this easily in JavaScript with just a few steps:

  1. Convert the SVG element to an SVG data uri
  2. Set the SVG data uri on an HTML img element
  3. Draw the HTML img element to canvas, which supports an API to return a PNG data uri

 

We do this in the sample below, which starts with an SVG element containing a single blue rectangle (1st from the left). We convert this SVG to a data uri and display it in an HTML img (2nd rectangle), draw this HTML img to canvas (3rd rectangle), and finally retrieve the PNG data uri and set it on another image tag (4th rectangle) to verify that it worked correctly.

svgToPng.png

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
  </head>
  <body>
    <!-- The SVG image that will be converted -->
    <svg id='sample' xmlns='http://www.w3.org/2000/svg' width='100' height='100'>
      <rect width='100' height='100' fill='#267db3'/>
        <rect width='1' height='1' fill='#ff0000'/>
    </svg>
    
    <!-- An img element for testing the SVG data uri -->
    <img id="imageWithSvgDataUri" width="100" height="100"></img>
    
    <!-- A canvas element for converting SVG to PNG data URI -->
    <canvas id="canvas" width="100" height="100"></canvas>
    
    <!-- An img element for testing the PNG data uri -->
    <img id="result" width="100" height="100"></img>
    
    <script type="text/javascript">
      // Get the SVG string and create the svg data uri
      var svg = document.getElementById('sample');
      var svgString = (new XMLSerializer()).serializeToString(svg);
      var svgDataUri = 'data:image/svg+xml;utf8,' + svgString;
      
      // For firefox, escape # characters to create valid data uri.
      svgDataUri = svgDataUri.replace(/#/g, '%23');
    
      // Set the SVG data uri on an img tag to make sure it's correct
      var image = document.getElementById('imageWithSvgDataUri');
      image.setAttribute('src', svgDataUri);
      
      // Draw the SVG to canvas and call toDataURL to convert to PNG data uri. The
      // image must be loaded prior to being drawn to canvas, which may be done
      // asynchronously by the browser.
      image.onload = function () {
        var canvas = document.getElementById('canvas');
        var ctx = canvas.getContext('2d');
        ctx.drawImage(image, 0, 0);
        var pngDataUri = canvas.toDataURL();
        
        var resultImage = document.getElementById('result');
        resultImage.setAttribute('src', pngDataUri);
      };
    </script>
  </body>
</html>

 

Some caveats of this approach:

  • As with any PNG image, it's important to know that the resulting visualization will no longer look good when scaled.
  • External references in the SVG, such as to style classes, remote downloaded fonts, or images may not be display in the resulting PNG. This is due to browser security limitations that require the image to be self contained.