32

Well, I need some help about convert .svg file/image to .png file/image...

I have a .svg image displayed on my page. It is saved on my server (as a .png file). I need to convert it to a .png file on demand (on click on a button) and save the .png file on the server (I will do this with an .ajax request).

But the problem is the conversion.

I read many things about the html5 Canvas, which can probably help doing what I need to do now, but I can't find any clear solution to my problem, and, tbh, I do not understand everything I found... So I need some clear advices/help about the way I have to do it.

Here is the "html idea" template :

<html>
    <body>
        <svg id="mySvg" width="300px" height="300px">
            <!-- my svg data -->
        </svg>
        <label id="button">Click to convert</label>
        <canvas id="myCanvas"></canvas>
    </body>
</html>

and some js :

<script>
    $("body").on("click","#button",function(){
        var svgText = $("#myViewer").outerHTML;
        var myCanvas = document.getElementById("canvas");
        var ctxt = myCanvas.getContext("2d");
    });
</script>

Then, I need to draw the svg into the Canvas, get back the base64 data, and save it in a .png file on my server... but... how? I read about so many different solutions that I'm actually... lost... I'm working on a jsfiddle, but I'm actually... nowhere... http://jsfiddle.net/xfh7nctk/6/ ... Thanks for reading / help

Kaiido
  • 123,334
  • 13
  • 219
  • 285
Julo0sS
  • 2,096
  • 5
  • 28
  • 52
  • ‘a .svg image [...] is saved [...] as a .png file‘ How does that work?! – Biffen Dec 01 '14 at 14:18
  • Have a look at http://stackoverflow.com/a/3769883/783219 – Prusse Dec 01 '14 at 14:43
  • Please checkout [this answer](https://stackoverflow.com/questions/3975499/convert-svg-to-image-jpeg-png-etc-in-the-browser/57154306#57154306) I provided here. It should solve your issue – Cels Jul 22 '19 at 22:09

2 Answers2

47

For inline SVG you'll need to:

  • Convert the SVG string to a Blob
  • Get an URL for the Blob
  • Create an image element and set the URL as src
  • When loaded (onload) you can draw the SVG as an image on canvas
  • Use toDataURL() to get the PNG file from canvas.

For example:

function drawInlineSVG(ctx, rawSVG, callback) {

    var svg = new Blob([rawSVG], {type:"image/svg+xml;charset=utf-8"}),
        domURL = self.URL || self.webkitURL || self,
        url = domURL.createObjectURL(svg),
        img = new Image;

    img.onload = function () {
        ctx.drawImage(this, 0, 0);     
        domURL.revokeObjectURL(url);
        callback(this);
    };

    img.src = url;
}

// usage:
drawInlineSVG(ctxt, svgText, function() {
    console.log(canvas.toDataURL());  // -> PNG data-uri
});

Of course, console.log here is just for example. Store/transfer the string instead here. (I would also recommend adding an onerror handler inside the method).

Also remember to set canvas size using either the width and height attributes, or from JavaScript using properties.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
  • this is perfect here and on JSFiddle.... but when I try to use it inside my project it looks like the draw function is not working... – Julo0sS Dec 01 '14 at 18:41
  • @Julo0sS what errors d you get in the console? did you add an onerror handler? Try inserting console.log's for the various stages and see where your code stops. Output the vars to see if they actually contains data or are undefined. Check that you grab the SVG outerHTML properly. My 2 cents. –  Dec 02 '14 at 01:25
  • what is the meaning of the syntax `self.URL || self.webkitURL || self ` and could you explain what the expression does ? – user305883 Dec 06 '15 at 22:51
  • 3
    @K3N How do you get `canvas` in `console.log(canvas.toDataURL());` ? – A J Oct 14 '16 at 10:41
  • 1
    problem with this answer is only a piece of the ger=nerated image appear converted to png image, not the whole svg image converted – Yousef Sep 10 '17 at 23:18
  • @Yousek this is because the canvas size. just increase it – daniel Nov 21 '17 at 17:03
  • @user1693593 404 on fiddle – Chris P Dec 06 '18 at 09:31
42

I come long after since some other question raised from this one because the accepted answer may produce undesirable behavior.

@K3N solution is almost right, but I would go against the use of svgElement.outerHTML.
Instead, one should prefer new XMLSerializer().serializeToString(svgElement).

Also, the use of blob and of the URL API is not necessary and a simple dataURI has more compatibility accross browsers.

So a complete version of this would be :

function drawInlineSVG(svgElement, ctx, callback) {
  var svgURL = new XMLSerializer().serializeToString(svgElement);
  var img = new Image();
  img.onload = function() {
    ctx.drawImage(this, 0, 0);
    callback();
  }
  img.src = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgURL);
}

// usage:
drawInlineSVG(document.querySelector('svg'), ctxt, function() {
  console.log(canvas.toDataURL())
});
Gooz
  • 1,106
  • 2
  • 9
  • 20
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • 2
    I tried the previous answer and if SVG has not the 'xmln' attribute it would fail. The answer of @Kaiido is a good improvement and worked also with "malformed" SVGs. – user305883 Dec 06 '15 at 22:57
  • 2
    @user305883, thanks for your feedback. Just to let you know that `` element doesn't have to have an `xmlns` declaration when appended to an HTML document. So your SVG wasn't "malformed", it's just that it is an svg element, not an svg document. dataURI should represent a document, hence the failure. XMLSerializer() does handle the conversion for us. – Kaiido Dec 07 '15 at 07:48
  • 1
    Hey guys - sorry for dragging this up on an already answered question. I am following this answer to the letter and everything is working fine, except when I get to `canvas.toDataURL()` I am getting a `SecurityError` . I am converting a Highcharts.js svg to png using this method so I am not sure where the issue with CORS is originating from (from what I've read this is a CORS issue??) The highcharts svg is all rendered in the browser. – Martin O Leary Feb 01 '17 at 16:41
  • @MartinOLeary This is not a CORS issue. Some UAs have security restrictions when drawing some svg elements on a canvas. On which browser does this happens? If IE < Edge, all svg tainted the canvas. Only workaround : use the canvas drawing methods to reproduce the svg (which is what a library like canvg does). For other UAs, you probably have a foreignObject element in your svg. Safari and in some cases chrome don't really like it, unfortunately, no other workaround than removing this element, or replacing it with the result of html2canvas on ots content. – Kaiido Feb 01 '17 at 23:45
  • Hi @Kaido, thanks for the reply. I am using IE11 (has to be IE11 and I know everyone using the system it will be on IE11). I have finally got it to work using canvg! Thanks! The method on this link [save file to SharePoint](http://www.cardinalsolutions.com/blog/2014/12/export_svg_sharepoint_library) is what got me exactly what I needed – Martin O Leary Feb 02 '17 at 12:08
  • Note - if size for canvas isn't specified it will default to 300 x 150. Use something like canvas.width = img.width; and canvas.height = img.height; after image.onload and before drawing image, to avoid the image size being set to default. Using CSS to set the dimensions won't work. See response by @k3N [link](https://stackoverflow.com/questions/17764012/image-being-clipped-when-copied-to-html-canvas-using-drawimage) – Tanya Gupta May 27 '17 at 17:18
  • 2
    @TanyaGupta, note that the root `` node must have absolutely set `width` and `height` attributes (not relative ones like `%`); note that IE didn't set an `width` nor an `height` (and neither their `naturalXXX` equivalents) on HTMLImages pointing to an svg document : for this browser, you'll need to grab the width yourself, either from the svg markup, either from the in document's node's `offsetXXX` ; note that all IE < Edge did taint the canvas when an svg has been drawn to it via `drawImage` ; that Safari >= 9 does taint the canvas when an `` element is being drawn on it. – Kaiido May 28 '17 at 02:17
  • @Kaiido I tried your script in IE but it is throwing the `XML5661:"Non-default namespace declarations must not have an empty URI."` issue. So far i'm trying with that I don't know how to fix this issues. Please give some suggestion . – mkHun Sep 29 '17 at 12:49
  • @mkHun It would require to see your svg markup to be able to tell for sure what's going on. The error message implis that you've got some namespaced attributes (`ns:attr=""`), while if embedded in html document, you should'nt have these. But that should still work if the namespaces are declared properly. IE quirks... – Kaiido Sep 30 '17 at 04:12
  • 1
    Seems the serializer doesn't handle references via , and so the reference is invalid in the resulting "standalone" document (svgURL). Any suggestions? – Victoria Mar 18 '18 at 07:43
  • @Victoria no, the serializer won't *download* anything, and hence, won't include the targeted resources pointed by `xlink:href` or other `urlFunc` or even fonts if they are not children of the element. You need to include these references yourself inside the `` element to be serialized, before you do the serialization if you want a standalone document. – Kaiido Mar 18 '18 at 07:47
  • are the kind of _local_ references I meant... no downloading needed... but gathering of more text to serialize. Maybe if the references were non-local, the URLs would then work!? – Victoria Mar 18 '18 at 20:01
  • @Victoria no the element with id `foo` must be appended in the serialized `` itself. Not in an other element, not externally. – Kaiido Mar 18 '18 at 22:59
  • Thanks. What about fonts? When I gather up all the href stuff into one tweaked serialized SVG, I still get nothing. Likely I have to add a font or two, as there are some lines and characters of interest. But surely I don't have to embed the font? Or is it impossible to use fonts in + ? – Victoria Mar 19 '18 at 03:48
  • @Victoria That depends what fonts: local ones can be accessed, networks one need to be appended as dataURL. – Kaiido Mar 19 '18 at 03:52
  • I was afraid that might be the answer; mine is on network. That probably kills this technique for me. Thanks for all your help. – Victoria Mar 19 '18 at 05:43
  • @Victoria https://stackoverflow.com/questions/41571622/how-to-include-css-style-when-converting-svg-to-png and https://stackoverflow.com/questions/42402584/how-to-use-google-fonts-in-canvas-when-drawing-dom-objects-in-svg/42405731#42405731 – Kaiido Mar 19 '18 at 05:47
  • @Crashalot https://stackoverflow.com/questions/42402584/how-to-use-google-fonts-in-canvas-when-drawing-dom-objects-in-svg/42405731#42405731 next 24h are for family ;-) Good luck with your project. – Kaiido Dec 31 '18 at 12:19