Convert SVG to PNG and maintain CSS integrity

d3.js, librsvg, png, svg

Solution

Style definitions for svg elements defined in stylesheets are not applied to the generated canvas. This can be patched by adding style definitions to the svg elements before calling canvg.

Inspired on this article, I've created this:

function generateStyleDefs(svgDomElement) {
  var styleDefs = "";
  var sheets = document.styleSheets;
  for (var i = 0; i < sheets.length; i++) {
    var rules = sheets[i].cssRules;
    for (var j = 0; j < rules.length; j++) {
      var rule = rules[j];
      if (rule.style) {
        var selectorText = rule.selectorText;
        var elems = svgDomElement.querySelectorAll(selectorText);

        if (elems.length) {
          styleDefs += selectorText + " { " + rule.style.cssText + " }\n";
        }
      }
    }
  }

  var s = document.createElement('style');
  s.setAttribute('type', 'text/css');
  s.innerHTML = "<![CDATA[\n" + styleDefs + "\n]]>";
  //somehow cdata section doesn't always work; you could use this instead:
  //s.innerHTML = styleDefs;

  var defs = document.createElement('defs');
  defs.appendChild(s);
  svgDomElement.insertBefore(defs, svgDomElement.firstChild);
}

// generate style definitions on the svg element(s)
generateStyleDefs(document.getElementById('svgElementId'));

Problem

I am currently using canvg() and Canvas2Image to copy my SVG to a canvas and then convert the canvas to PNG. I would like to maintain the image format and not use PDF. How can I maintain the CSS integrity? Chart is made using NVD3.js. ``` downloadPhoto: function() { var chartArea = document.getElementsByTagName('svg')[0].parentNode; var svg = chartArea.innerHTML; var canvas = document.createElement('canvas'); canvas.setAttribute('width', chartArea.offsetWidth); canvas.setAttribute('height', chartArea.offsetHeight); canvas.setAttribute('display', 'none'); canvas.setAttribute( 'style', 'position: absolute; ' + 'top: ' + (-chartArea.offsetHeight * 2) + 'px;' + 'left: ' + (-chartArea.offsetWidth * 2) + 'px;'); document.body.appendChild(canvas); canvg(canvas, svg); Canvas2Image.saveAsPNG(canvas); canvas.parentNode.removeChild(canvas); } ```

Original source