2

I need to do a svg export png image function. First I generate svg to base64, with the base64 header type too svg+xml, then

var image=new Image();
image.src=base64Code;
image.onload = function() {
      var canvas = document.createElement('canvas');
      var context = canvas.getContext('2d');
      canvas.width = image.width;
      canvas.height = image.width;
      context.drawImage(image, 0, 0);
      png = canvas.toDataURL("image/png",1);
}`

My canvas.width/height may be very large.
When I use canvas.toDataURL it returns "data:;". When the canvas.width/height is more reasonable, the result is correct.

Is there any good way to deal this? Or use javascript to convert from svg+xml to .png?

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • When you say very large, how large is it ? Bigger than these [max sizes](http://stackoverflow.com/questions/6081483/maximum-size-of-a-canvas-element) ? If so, yes, don't use a canvas. Otherwise, you could try [`canvas.toBlob`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) method, which theoretically would have less memory impact and thus should be able to return bigger images. But if you're able to provide a server-side conversion, then go with it, you'll get far better results with e.g batik than with javascript. – Kaiido May 09 '17 at 08:10
  • So actually `toBlob` and `toDataURL` have the same limit (around 16380*16380 on my chrome and around 11150*11150 on my FF). But one interesting thing is that for `toDataURL` chrome does return the string you've got, while FF does throw an `NSIndexError`, and for `toBlob` chrome does return null in the callback while FF doesn't even execute the callback, nor does it throw any error... – Kaiido May 09 '17 at 08:29
  • I tryed to use batik to generate svg file to png file or svg code to png file but In my svg,It has tag ,the tag has tag ,when I generate svg the do not show – 流年灬异彩 May 09 '17 at 12:10
  • No batik is not able to render html (which is in your foreignObject) for these your only option is an HTML renderer that will also be able to render SVG (I can think of web browsers on the top of my head). But then we fall back in the canvas' max-size problem + the fact that only FF, chrome and Edge(?) do support rendering foreignObject on a canvas without tainting it for export. So you'd at least have to set a maximum size for your canvas (you could also split the image in multiple ones and then merge them on server) or you could try to grab a screenshot from an headless browser server-side. – Kaiido May 09 '17 at 12:28
  • [phantomjs](http://phantomjs.org/screen-capture.html) should be able to do it. Though I never tested with foreignObjects – Kaiido May 09 '17 at 12:31

2 Answers2

1

Canvas element has maximum size which will be different across browser implementations. You can find a good list of these maximum dimensions in this Q/A.

They also have limits for the export methods. In my Chrome, toDataURL returns the same data:; as you've got for canvas around 16380 * 16380 wide and my Firefox does throw an NS_ERROR_FAILURE at around 11150 * 11150. Other browsers might have different values depending on their own implementation.

So, if you really want to pass through canvas, you will have to limit the size of your canvas to these maximum areas.

Now, if you can do the conversion server-side, you can go with it. Batik is known to be a good SVG UA and should be able to convert your SVGs correctly, except when there is also HTML to render inside an SVG's <foreignObject> element.

In this case, an headless browser like phantomjs, allowing to take real screenshots of a rendered page seems to be the best way.

An other way would be to draw your large SVG onto smaller canvas and merge the resulting PNG images either server-side or through byte manipulation (might need some extra work).

Wolverine
  • 1,712
  • 1
  • 15
  • 18
Kaiido
  • 123,334
  • 13
  • 219
  • 285
-1

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

ctx.strokeRect(5, 5, 25, 15);
ctx.scale(2, 2);
ctx.strokeRect(5, 5, 25, 15);
</script> 

</body>
</html>

HTML canvas scale() Method

you can use this method, maybe it can work

return 'data:;' maybe the url is too large

Amirhossein
  • 1,148
  • 3
  • 15
  • 34