Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert very large SVG to PNG using <canvas>

I'm trying to convert a large SVG (it's data URL is about 750000 - 1000000 characters) to a PNG by passing it's data url through an image and into a canvas but the image is only loading about 1/4 of the SVG.

Creating via:

var svg_xml = (new XMLSerializer()).serializeToString(svg),
    url = 'data:image/svg+xml;base64,' + btoa(svg_xml);

var img = new Image();
img.width = 730;
img.height = 300;
img.onload = function(){
    var canvas = document.create('canvas');
    canvas.width = 730;
    canvas.height = 300;

    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, 730, 300);

    callbackFn(canvas.toDataURL('image/png');
}
img.src = url

Edit

I've tried implementing canvg to draw the SVG but the DataURL produced results in a blank image:

var svg_xml = (new XMLSerializer()).serializeToString(svg);
var canvas = document.createElement('canvas');
canvas.width = 730;
canvas.height = 300;

var ctx = canvas.getContext('2d');
ctx.drawSvg(svg_xml, 0, 0, 730, 300);
callbackFn(canvas.toDataURL('image/png');

Is there anything wrong with the method I've used?

Further Edit

I'm now fairly convinced that it's the canvas failing to draw the whole image as I tried implementing a Blob solution to the same effect:

var svg_xml = (new XMLSerializer()).serializeToString(svg),
    blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}),
    url = window.URL.createObjectURL(blob);

var img = new Image();
img.width = 730;
img.height = 300;
img.onload = function(){
    var canvas = document.create('canvas');
    canvas.width = 730;
    canvas.height = 300;

    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, 730, 300);

    window.URL.revokeObjectURL(url);
    callbackFn(canvas.toDataURL('image/png');
}
img.src = url   

The image again loads fine and going to the URL (before it's revoked) displays the image fine as well.

The length of the canvas dataURL is not consistent so I don't think that's maxing out, is there a way of detecting the canvas size? The application is only supported for Chrome and FireFox.

like image 912
matts1189 Avatar asked Aug 26 '15 15:08

matts1189


People also ask

How do I convert SVG to PNG for free?

SVG to PNG – Convert SVG files to PNG Online Use this free online SVG to PNG converter to convert SVG files to PNG images, quickly and easily, without having to install any software. Click the UPLOAD FILES button and select up to 20 SVG files you wish to convert.

How do I open SVG files on my computer?

You can also click to select SVG files using your operating system's file picker. Another method is to press the keyboard shortcut Ctrl+V (⌘+V on Mac) to paste an SVG file you have copied to clipboard. Converting a folder with SVG files to PNG is also supported: simply paste or drag and drop it.

What is a PNG file?

Portable Network Graphics (PNG) is a raster-based file type that compresses images for portability. PNG images can have RGB or RGBA colors and support transparency, which makes them perfect for use in icons, or graphic designs. PNG also supports animations with better transparency (try our GIF to APNG ).

What is SVG (Scalable Vector Graphics) File?

What is an SVG (Scalable Vector Graphics) file? Scalable Vector Graphics (SVG) is a resolution-independent, open-standard file format. It is based on Extensible Markup Language ( XML ), uses vector graphics, and supports limited animation.


Video Answer


1 Answers

Working fiddle.

HTML:

    <div>
        <svg xmlns="http://www.w3.org/2000/svg"
              width="526" height="233">
          <rect x="13" y="14" width="500" height="200" rx="50" ry="100"
              fill="none" stroke="blue" stroke-width="10" />
        </svg>
        <a id='imgId'>Save</a>
    </div>
    <canvas></canvas>

JavaScript:

var svg = document.getElementsByTagName('svg')[0];
var svg_xml = (new XMLSerializer()).serializeToString(svg),
    blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}),
    url = window.URL.createObjectURL(blob);

var img = new Image();
img.width = 730;
img.height = 300;
img.onload = function(){
    var canvas = document.createElement('canvas');
    canvas.width = 730;
    canvas.height = 300;

    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, 730, 300);

    window.URL.revokeObjectURL(url);
    var canvasdata = canvas.toDataURL('image/png');
    var a = document.getElementById('imgId');
    a.download = "export_" + Date.now() + ".png";
    a.href=canvasdata;   
}
img.src = url

Your question:

Why image is only loading about 1/4 of the SVG?

Answer:

Just follow these rules:

  1. x of <rect/> + width of <rect/> <= width of <svg/>
  2. y of <rect/> + height of <rect/> <= height of <svg/>

For example:

<svg xmlns="http://www.w3.org/2000/svg" width="500" height="200">
     <rect x="10" y="10" width="550" height="250" rx="50" ry="100"
                  fill="none" stroke="blue" stroke-width="10" />
</svg>

Here, x of <rect/> = 10, width of <rect/> = 550, width of <svg> = 500

so, 10+550>500

In this case image will be partially rendered.

Hope this will solve your problem.

like image 88
Khalid Hussain Avatar answered Oct 07 '22 21:10

Khalid Hussain