how to save/ export inline SVG styled with css from browser to image file how to save/ export inline SVG styled with css from browser to image file javascript javascript

how to save/ export inline SVG styled with css from browser to image file


Why not copying the SVG node/tree and then take the styles, as defined per tag (You will need the original tree, as the copy may be without styles in case the element is part of a longer tree). This ensures that you are only copying those styles relevant as set in the CSS file.The export type could easily be set before sending the package to the blob

var ContainerElements = ["svg","g"];var RelevantStyles = {"rect":["fill","stroke","stroke-width"],"path":["fill","stroke","stroke-width"],"circle":["fill","stroke","stroke-width"],"line":["stroke","stroke-width"],"text":["fill","font-size","text-anchor"],"polygon":["stroke","fill"]};function read_Element(ParentNode, OrigData){    var Children = ParentNode.childNodes;    var OrigChildDat = OrigData.childNodes;         for (var cd = 0; cd < Children.length; cd++){        var Child = Children[cd];        var TagName = Child.tagName;        if (ContainerElements.indexOf(TagName) != -1){            read_Element(Child, OrigChildDat[cd])        } else if (TagName in RelevantStyles){            var StyleDef = window.getComputedStyle(OrigChildDat[cd]);            var StyleString = "";            for (var st = 0; st < RelevantStyles[TagName].length; st++){                StyleString += RelevantStyles[TagName][st] + ":" + StyleDef.getPropertyValue(RelevantStyles[TagName][st]) + "; ";            }            Child.setAttribute("style",StyleString);        }    }}function export_StyledSVG(SVGElem){    var oDOM = SVGElem.cloneNode(true)    read_Element(oDOM, SVGElem)    var data = new XMLSerializer().serializeToString(oDOM);    var svg = new Blob([data], { type: "image/svg+xml;charset=utf-8" });    var url = URL.createObjectURL(svg);    var link = document.createElement("a");    link.setAttribute("target","_blank");    var Text = document.createTextNode("Export");    link.appendChild(Text);    link.href=url;    document.body.appendChild(link);}


You will need to explicitly set the calculated css styles as SVG dom style properties for each SVG element before saving it.Here is an example:

<html>    <body>    <!-- in this example the inline svg has black backgroud-->    <svg id="svg" xmlns="http://www.w3.org/2000/svg" version="1.1" height="190">        <polygon id="polygon" points="100,10 40,180 190,60 10,60 160,180" style="stroke:purple;stroke-width:5;">    </svg>    <style>        /* the external svg style makes svg shape background red */        polygon         {            fill:red;        }    </style><svg id="emptysvg" xmlns="http://www.w3.org/2000/svg" version="1.1" height="2"/><br/>image original:<canvas id="canvasOriginal" height="190" width="190" ></canvas><br/>image computed:<canvas id="canvasComputed" height="190" width="190" ></canvas><script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script><script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script> <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/StackBlur.js"></script><script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script> <script src="http://www.nihilogic.dk/labs/canvas2image/canvas2image.js"></script><script type="text/javascript">var svg = $('#svg')[0];var canvasOriginal = $('#canvasOriginal')[0];var ctxOriginal = canvasOriginal.getContext('2d');var canvasComputed=$('#canvasComputed')[0];var ctxConverted=canvasComputed.getContext("2d");// this saves the inline svg to canvas without external csscanvg('canvasOriginal', new XMLSerializer().serializeToString(svg));// we need to calculate the difference between the empty svg and oursvar emptySvgDeclarationComputed = getComputedStyle($('#emptysvg')[0]);function explicitlySetStyle (element) {    var cSSStyleDeclarationComputed = getComputedStyle(element);    var i, len, key, value;    var computedStyleStr = "";    for (i=0, len=cSSStyleDeclarationComputed.length; i<len; i++) {        key=cSSStyleDeclarationComputed[i];        value=cSSStyleDeclarationComputed.getPropertyValue(key);        if (value!==emptySvgDeclarationComputed.getPropertyValue(key)) {            computedStyleStr+=key+":"+value+";";        }    }    element.setAttribute('style', computedStyleStr);}function traverse(obj){    var tree = [];    tree.push(obj);    if (obj.hasChildNodes()) {        var child = obj.firstChild;        while (child) {            if (child.nodeType === 1 && child.nodeName != 'SCRIPT'){                tree.push(child);            }            child = child.nextSibling;        }    }    return tree;}// hardcode computed css styles inside svgvar allElements = traverse(svg);var i = allElements.length;while (i--){    explicitlySetStyle(allElements[i]);}// this saves the inline svg to canvas with computed stylescanvg('canvasComputed', new XMLSerializer().serializeToString(svg));$("canvas").click(function (event) {    Canvas2Image.saveAsPNG(event.target);});</script>    </body></html>


If your css rules are not too much complicated, you can do the following steps:

  1. Read the .css file, which contains all the css rule. If required, you can use a different css file and put it on the server, which you can only use for this purpose.

    function readTextFile(file) {    var rawFile = new XMLHttpRequest();    var allText = '';    rawFile.open("GET", file, false);    rawFile.onreadystatechange = function () {        if(rawFile.readyState === 4) {            if(rawFile.status === 200 || rawFile.status == 0) {                allText = rawFile.responseText;            }        }    };    rawFile.send(null);    return allText;}var svg_style = readTextFile(base_url + '/css/svg_sm_dashboard.css');
  2. Now apply the style on all the svg elements

    var all_style = svg_style.replace(/\r?\n|\r/g,'').split('}');all_style.forEach(function(el) {    if (el.trim() != '') {        var full_rule_string = el.split('{');        var selector = full_rule_string[0].trim();        var all_rule = full_rule_string[1].split(';');        all_rule.forEach(function (elem) {            if (elem.trim() != '') {                var attr_value = elem.split(':');                //d3.selectAll(selector).style(attr_value[0].trim() + '', attr_value[1].trim() + '');                var prop = attr_value[0].trim();                var value = attr_value[1].trim();                d3.selectAll(selector).each(function(d, i){                    if(!this.getAttribute(prop) && !this.style[prop]){                        d3.select(this).style(prop + '', value + '');                    }                });            }       });   }});
  3. Use canvg to convert it

    $('body').after('<canvas id="sm_canvas" style="display=none;"></canvas>');var canvas = document.getElementById('sm_canvas');canvg(canvas, $("<div>").append($('svg').clone()).html());
  4. Get Image from the canvas

    var imgData = canvas.toDataURL('image/jpeg');