I'm trying to save the canvas to the file from the web page.
The canvas is pretty complicated and has been built from several images (few semi-transparent .png files, 2 svg elements, and 4 other canvases) and no matter how I'm trying to save it, using canvas.toDataURL()
method or using domtoimage [library] (https://github.com/tsayen/dom-to-image) or canvas2image or fileSaver or canvasToBLob libraries - the result is the same: an image without svg(and <image>
element inside) parts. So i'm getting only the parts, that were built from canvas. I read about the 'tainted' canvases, but the images host server is the same as webpage is.
Moreover I'm confused, because if I saving the canvas by clicking RCM and selecting "Save image as" function - it saves exactly what I need - the full picture.
The whole code is huge and the saving options are different, so I will put here only one saving option:
domtoimage.toBlob(canvasElement)
.then(function (blob) {
console.log(blob);
window.saveAs(blob, 'my-node.png');
});
The picture on the left is what im getting when using 'save image as' feature in browser, and on the right is the image saved by js through the toBlob
will be happy to get any suggestions of how to save the full image automatically :)
I'll take the opportunity of your edit to post this as a real answer, since you based yours (which you should have posted as a self-answer b.t.w) on a comment of mines asking you for more clarification.
So, as we found out, your problem was that all the images weren't loaded/drawn when you called the export method, hence, these images were missing in the output.
The canvg
function, and its shortcut ctx.drawSvg
, can be asynchronous. Normally, when only shapes are being rendered it is not, but since here you are loading external content, wrapped in an SVGImage (<image>
) element, it can't be synchronous.
But, there is a renderCallback
option that you can add to your canvg call. Since you do use the ctx.drawSVG
, and that this method has some extra parameters (dx, dy, dwidth, dheight) compared to the original canvg
, you need to call it like so :
ctx.drawSvg(yourSVGMarkup, 0, 0, null, null, {renderCallback: yourCallbackFunction});
var str = new XMLSerializer().serializeToString(document.querySelector('svg'));
canvas.getContext('2d').drawSvg(str, 0, 0, null, null, {
renderCallback: function() {
console.log('done');
}
});
console.log('doing');
<script src="https://cdn.rawgit.com/canvg/canvg/master/canvg.js"></script>
<svg width="300" height="150" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" x="0" y="0" height="100" width="100" />
</svg>
<canvas id="canvas"></canvas>