Convert SVG to image in PNG
Asked Answered
B

2

1

i am converting angular nvd3 chart to svg using html2canvas and canvg plugings but when i convert pie chart to png then i looks same as chart but when i convert line chart or area chart then its background goes to black and some circle drown on image. My code is

var svgElements = $("#container").find('svg');

            //replace all svgs with a temp canvas
            svgElements.each(function () {
                var canvas, xml;

                // canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
                $.each($(this).find('[style*=em]'), function (index, el) {
                    $(this).css('font-size', getStyle(el, 'font-size'));
                });

                canvas = document.createElement("canvas");
                canvas.className = "screenShotTempCanvas";
                //convert SVG into a XML string
                xml = (new XMLSerializer()).serializeToString(this);

                // Removing the name space as IE throws an error
                xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');

                //draw the SVG onto a canvas
                canvg(canvas, xml);
                $(canvas).insertAfter(this);
                //hide the SVG element
                ////this.className = "tempHide";
                $(this).attr('class', 'tempHide');
                $(this).hide();
            });


            html2canvas($("#container"), {
                onrendered: function (canvas) {
                    var a = document.createElement("a");
                    a.download = "Dashboard.png";
                    a.href = canvas.toDataURL("image/png");
                    a.click();
                    var imgData = canvas.toDataURL('image/png');

                    var doc = new jsPDF('p', 'mm','a4');
                    var width = doc.internal.pageSize.width;    
                    var height = doc.internal.pageSize.height;

                    doc.addImage(imgData, 'PNG',  0, 0, width, height);
                    doc.save('Dashboard.pdf');
                }
            });

            $("#container").find('.screenShotTempCanvas').remove();
            $("#container").find('.tempHide').show().removeClass('tempHide');

this is area chart image with some unknown circle on chart

Help me guys. Thanks In Advance

Brochette answered 27/12, 2016 at 6:57 Comment(4)
Do you have some styling applied on your svg nodes from a <style> element ? If so, you need to include it in your svg node before calling the XMLSerializer.Scoville
@Scoville no styling applied on this.Brochette
Could you make a jsfiddle so we can see how is rendered your svg ?Scoville
@Scoville plnkr.co/edit/UaI7rtfMLxxCKt5xy6s3?p=previewBrochette
S
3

Your svg elements are being styled by the external stylesheet nv.d3.min.css .

canvg seems unable to access external style sheets, so you need to append it directly in your svg node.

To do so, if your style sheet is hosted on the same domain as your scripts, you can do something like :

var sheets = document.styleSheets;
var styleStr = '';
Array.prototype.forEach.call(sheets, function(sheet){
    try{ // we need a try-catch block for external stylesheets that could be there...
        styleStr += Array.prototype.reduce.call(sheet.cssRules, function(a, b){
            return a + b.cssText; // just concatenate all our cssRules' text
            }, "");
        }
    catch(e){console.log(e);}
});
// create our svg nodes that will hold all these rules
var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
var style = document.createElementNS('http://www.w3.org/2000/svg', 'style');
style.innerHTML = styleStr;
defs.appendChild(style);
// now append it in your svg node
thesvg[0].insertBefore(defs, thesvg[0].firstElementChild);

So now you can call the XMLSerializer, and canvg will be happy.
(note that this is not only a canvg limitation, the same applies for every way to draw an svg on a canvas).

Forked plunkr, where I copied the nv.d3.min.css's content to a same-origin style.css.

Scoville answered 27/12, 2016 at 13:29 Comment(3)
@dkc007, han, this is a chrome bug and an angular bad implementation.. ng uses some hackish [ng\:something] selector, while they should use [ng|something]... Chrome accepts happily this hack for rendering, but it stores only [ng:something] in the stylesheet rules, while this later is invalid and throws this error... here is an other fork which quick-fixes it, by avoiding the stylesheet which has these rules : plnkr.co/edit/ZgT2P4Tu0Z9x63QwPNFB?p=previewScoville
please check this plunker i am unable to see any image in downloaded image plnkr.co/edit/UaI7rtfMLxxCKt5xy6s3?p=previewBrochette
@dkc007 I told you I am at work, which means that I've got a job that gives me money that I need and weirdly enough, my boss (the one that gives me money) prefer to see me working for him in working hours rather than for some unknown person on the internet. You'll have to wait.Scoville
P
1

Very late to the conversation but I just wanted to add that the solution as described by Kaiido, put very simply, is to embed the styles into the SVG document directly.

In order to do this, you manipulate the DOM to make the SVG element look like this:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1">
   <defs>
     <style>
       .rectangleStyle{
           width:200px;
           height:100px;
           stroke:black;
           stroke-width: 6;
           fill: green;
       }       
     </style>
   </defs>
   <rect class="rectangleStyle"/>
</svg>
Poinsettia answered 18/7, 2018 at 13:46 Comment(1)
thank you, this is a nice compliment to Kaiido's answer.Braille

© 2022 - 2024 — McMap. All rights reserved.