Tainted Canvas - CORS issue?


#1

I’m building an Animation creation app in Electron using greensock.com’s awesome GSAP library. All the animation takes place inside a master SVG. To export the animations, I step through each frame of the animation and capture the master svg to a blob, assign the blob to an img src and then use canvas.toDataURL to create a series of PNGs which are then converted to various output formats using FFMPEG. Everything works great until I attempt to add some basic text to a foreignObject inside the master SVG. I get the following error:

Uncaught SecurityError: Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported.

Everything I read says all you should have to do is set the crossOrigin property on the image to “Anonymous” but that doesn’t solve anything. I also read that you can set ‘web-security’ to false in webPreferences for BrowserWindow so tried that as well but no banana.

I’ve been using Electron 1.2.8 so tried upgrading to 1.3.4 (because there was a CORS fix of some kind) and that didn’t help.

Here’s what the masterSVG looks like when testing the foreignObject:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="800" height="600" x="0" y="0" id="stage-master" style="background: rgb(255, 255, 255);">
  <foreignObject width="100%" height="100%">
    <div xmlns="http://www.w3.org/1999/xhtml" style="font-size: 40px;">
      <h1 style=" color: #000000;">Testing</h1>
    </div>
  </foreignObject>
  <!-- other SVG elements here -->
</svg>

Without the foreignObject, it works beautifully. I’m not even adding an image, just a piece of text and it’s there when the file loads.

Here’s the script that causes the error (there’s more to the script than what follows here but this is the gist of it)…

var xml  = new XMLSerializer().serializeToString(masterSVG);
var blob = new Blob([xml], { type: "image/svg+xml" });
var img  = new Image();

img.crossOrigin = "Anonymous";

img.onload = function() {
  blob.close();
  ctx.drawImage(img, 0, 0);
  var url = canvas.toDataURL("image/png");

  var png = new Image();
  png.src = url;
  var padded = pad(current,5);
  var filename = `img${padded}`;
  var fullPath = base64Img.imgSync(url, pngFolder, filename);

  URL.revokeObjectURL(url);
}

img.src = URL.createObjectURL(blob);

It fails at…
var url = canvas.toDataURL("image/png");

Probably no bearing on the problem, but I’m using a Mac to dev. Man, this is killing me. Without being able to load in a foreignObject, all I can use are SVGs. Anyone have a clue as to what’s going on here?

Thanks in advance.


#2

This StackOverflow answer should help.


#3

Did the trick. Thanks!