How to Fix "The canvas has been tainted by cross-origin data" Errors
Greetings, friends! Has this ever happened to you? You're working with the HTML Canvas API, having the time of your life, but then you get an unexpected error:
Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
Ugh! This error just spoiled your fun! In this tutorial, I will discuss how to resolve this issue!
Let's use CodePen to create a new "Pen" where we can test out some HTML, CSS, and JavaScript code. I'm guessing they got the name, "pen," from the word, "playpen" 🤔. Anyhoo, let's insert the following in the HTML section of our Pen.
<canvas id="canvas" width="1000" height="535"></canvas>
In the CSS section, insert the following:
#canvas {
border: 1px solid black;
}
This border just lets us see where the canvas is, so we can make sure things the canvas is rendering properly. Next, we'll insert the following JavaScript code to fetch an image from a remote server.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const image = new Image();
image.src = 'https://images.pexels.com/photos/12043242/pexels-photo-12043242.jpeg';
image.onload = () => {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
};
CodePen will make a request to an external website when the code is run. It will grab a free stock photo from Pexels. Our code will then draw this image to the canvas.
So far, so good! Now, what might happen if we were to make this image "dirty" or "tainted?" By that, I mean we alter the pixel values of the canvas, so they're different from the original. Let's make a removeRed
function that removes all red pixels from the canvas.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const image = new Image();
image.src = "https://images.pexels.com/photos/12043242/pexels-photo-12043242.jpeg";
image.onload = () => {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
removeRed();
};
const removeRed = () => {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = 0; // remove red color from each pixel
}
ctx.putImageData(imageData, 0, 0);
};
When we run this code, you'll see that nasty error appear. The canvas has been tainted by cross-origin data.
As a security precaution, the browser will warn you that the canvas has been tainted. This protects users from having private data exposed from images that pull information from remote servers without permission. Hackers are very crafty! You never know what new diabolical methods they'll come up with!
To fix this problem, we need to allow cross-origin use of images and the canvas. This one line will solve the issue!
image.crossOrigin = "Anonymous";
This line will allow non-authenticated downloading of the image cross-origin (between different websites or subdomains). In a real production app, you'd only do this if you trust the website you're pulling resources from. Once we add this line to our code, we end up with the following:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const image = new Image();
image.src = "https://images.pexels.com/photos/12043242/pexels-photo-12043242.jpeg";
image.crossOrigin = "Anonymous";
image.onload = () => {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
removeRed();
};
const removeRed = () => {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = 0; // remove red color from each pixel
}
ctx.putImageData(imageData, 0, 0);
};
When the code runs, you should see the original image but with the red removed! So pretty! 😲
If you still get an error about the canvas being tainted by cross-origin data, then this issue could be on the server side. The server must be configured to host images with the Access-Control-Allow-Origin header configured to permit cross-origin access to image files.