Reputation: 125
After I draw the canvas from an image(local file), I try to export it with the command ctx.canvas.toDataURL("image/png")
But there is an error:
DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
I already searched in google. They said this is the problem of Cross. So, I added command:
image.crossOrigin = '*';
But this is useless for my project. Actually, my project is building on local without any server. So, I have no idea why there is the problem of cross-domain.
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
var image = new Image();
image.onload = function() {
image.crossOrigin = '*';
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
generate() {
var p1 = loadImageAsync(this.textures[1]);
var p2 = loadImageAsync(this.textures[2]);
var p3 = loadImageAsync(this.textures[3]);
var ctx = document.createElement("canvas")
.getContext("2d");
ctx.canvas.width = this.width;
ctx.canvas.height = this.height;
var rows = ~~(this.width / 70);
var cols = ~~(this.height / 70);
Promise.all([p1, p2, p3])
.then(imgs => {
for (let x = 0, i = 0; i < rows; x += 70, i++) {
for (let y = 630, j = 0; j < cols; y -= 70, j++) {
this.resource[i].forEach(item => {
switch (item) {
case 1:
ctx.drawImage(imgs[0], x, y, 70, 70);
break;
case 2:
ctx.drawImage(imgs[1], x, y, 70, 70);
break;
case 3:
ctx.drawImage(imgs[2], x, y, 70, 70);
break;
default:
}
});
}
}
//window.ctx = ctx;
this.image.crossOrigin = '*';
this.image.src = ctx.canvas.toDataURL("image/png");
});
};
Upvotes: 6
Views: 28853
Reputation:
When you load images, if they are from another domain they will be marked as cross domain unless they have CORS permissions. This includes loading files from file://
. Cross domain images without CORS permissions will taint the canvas if using canvas 2d, and are not usable at all if using WebGL
If the files are local it's best to use a simple server. Here's one and here's a bunch more
If the images are actually cross domain then you need to request CORS permission by setting img.crossOrigin
and the server needs to return the correct headers for the images. I believe the only header needed is
Access-Control-Allow-Origin: *
You have to set img.crossOrigin
BEFORE you set img.src
. Setting img.crossOrigin
tells the browser to request the permission from the server. The request is sent the moment you set img.src
.
Let's try it with an imgur URL which I happen to know supports CORS, also your URL you mentioned, and one from my site which I know does NOT support CORS
[
{ url: "https://i.imgur.com/TSiyiJv.jpg", crossOrigin: "*", },
{ url: "https://newmario.herokuapp.com/img/grassMid.png", crossOrigin: "*", },
{ url: "https://greggman.com/images/echidna.jpg", /* NO CORS */ },
].forEach(loadImage);
function loadImage(info) {
const url = info.url;
const img = new Image()
img.onload = function() {
const ctx = document.createElement("canvas").getContext("2d");
try {
ctx.drawImage(img, 0, 0);
ctx.canvas.toDataURL();
log("got CORS permission for:", url);
} catch(e) {
log("**NO** CORS permission for:", url);
}
}
img.onerror = function() {
log("could not load image:", url);
}
img.crossOrigin = info.crossOrigin;
img.src = url;
}
function log(...args) {
const elem = document.createElement("pre");
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
pre { margin: 0; }
My results, the imgur image works, yours works, mine does not (as expected)
Note that there are 8 cases
| local/remote | crossOrigin | CORS headers | Result
-+-----------------+---------------+---------------+---------------------
1| local | not set | no | can use image
-+-----------------+---------------+---------------+----------------------
2| local | not set | yes | can use image
-+-----------------+---------------+---------------+----------------------
3| local | set | no | can use image
-+-----------------+---------------+---------------+----------------------
4| local | set | yes | can use image
-+-----------------+---------------+---------------+----------------------
5| remote | not set | no | can use image in canvas 2d
| | | | but it will dirty the canvas.
| | | | Can not use with WebGL
-+-----------------+---------------+---------------+----------------------
6| remote | not set | yes | can use image in canvas 2d
| | | | but it will dirty the canvas
| | | | Can not use with WebGL
-+-----------------+---------------+---------------+----------------------
7| remote | set | no | image fails to load
-+-----------------+---------------+---------------+----------------------
8| remote | set | yes | can use image
-+-----------------+---------------+---------------+----------------------
Upvotes: 1
Reputation: 1
set useCORS
to ture can solve this issue
html2Canvas(document.querySelector('#pdfDom'), {useCORS: true}).then((canvas) =>
{
let pageData = canvas.toDataURL('image/jpeg', 1.0);
}
Upvotes: 0
Reputation: 32879
You need to set crossOrigin
for the image outside the onload function.
return new Promise(function(resolve, reject) {
var image = new Image();
image.crossOrigin = '*'; //<-- set here
image.onload = function() {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
Upvotes: 14