JavaScript: toDataUrl () throws "Security error: infected canvases may not be exported."

I have an HTML5 canvas on which I draw an image from svg.

HTML

<canvas id="canvas" width="600" height="320"></canvas> 

Javascript

 var DOMURL = window.URL || window.webkitURL || window; var data = '<svg xmlns="http://www.w3.org/2000/svg" width="600" height="320">'+ '<foreignObject width="100%" height="100%">'+ '<style>'+ 'foreignObject {'+ 'background-color: #000;'+ 'color: #fff'+ 'border-radius: 10px;'+ '}'+ 'h1 {'+ 'color: #2acabd;'+ 'font: 25px arial;'+ 'font-weight: bold;'+ 'text-align: center;'+ '}'+ 'h2 {'+ 'margin: 0;'+ 'color: #2acabd;'+ 'font: 15px arial;'+ '}'+ 'p {'+ 'color: #fff;'+ '}'+ '</style>'+ '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size: 40px;">'+ '<h1>Heading</h1>'+ '<div>'+ '<div id="details-wrapper">'+ '<h2>Full Name</h2>'+ '<p>Alan Johnson</p>'+ '<h2>Date of Birth</h2>'+ '<p>7th November 1988</p>'+ '<p><span id="user-id">34329483028493284093284432</span></p>'+ '</div>'+ '</div>'+ '</div>'+ '</foreignObject>'+ '</svg>'; var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); img = new Image(); img.setAttribute("crossOrigin", "anonymous"); var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'}); var url = DOMURL.createObjectURL(svg); img.onload = function() { ctx.drawImage(img, 0, 0); DOMURL.revokeObjectURL(url); console.log(canvas.toDataURL()); } img.src = url; 

(JS Fiddle: https://jsfiddle.net/LondonAppDev/qnpcg8th/1/ )

When I call canvas.toDataURL() , I get an exception:

 (index):98 Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. 

I saw many other questions and answers about stack overflow related to this exception. My problem is different because (as you can see) at no time do I include images from another domain in my SVG or canvas.

I assume the problem is that I am creating an object DOMURL.createObjectURL with DOMURL.createObjectURL .

I know that in different browsers there are some compatibility problems, however this application needs to be run only in Chrome. Also, drawing text directly on the canvas is not an option; I have to do this through svg.

Any ideas on how I can get around this problem and successfully get my canvas PNG?

+5
source share
2 answers

I solved this by converting svg to data url instead of blob.

I removed var url = DOMURL.createObjectURL(svg); and replaced img.src = url; on this:

 function buildSvgImageUrl(svg) { b64 = window.btoa(svg); return "data:image/svg+xml;base64," + b64; } img.src = buildSvgImageUrl(data); 

Now it works flawlessly.

+12
source

This one is for the protection and privacy of users.
To draw a <foreignObject> on the canvas, you can leak some information about users, and before that the chrome team thought that they did not have enough security measures to prevent this from damaging the canvas.

Here is this chrome error report about this issue.

But, as OP found out, they had an implementation error that forgot to set this restriction on the version of dataURI.
I published an error report message saying that they do not contaminate the web with dataURI.

All this leads to the lever of the previous restrictions, so in future versions of chrome we can draw <foreignObject> on the canvas without messing it up, even using BlobURI.

But keep in mind that Safari still has the same restriction (without an implementation error, that is, the dataURI handler does not work there), and that IE <Edge does not support the <foreignObject> element and covers the canvas when SVG any was written to it, and that FF removes all UserAgent and OS styles (which leads to different results than what you might expect).

The real workaround then is not to use this hack to draw your elements, but to draw all your HTML using the CanvasAPI drawing methods (just like html2canvas ).

+1
source

All Articles