无法在 HTMLCanvasElement 上执行 toDataURL

问题描述 投票:0回答:3

从图像(本地文件)绘制画布后,我尝试使用命令

ctx.canvas.toDataURL("image/png")

将其导出

但是有一个错误:

DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

我已经在谷歌搜索过了。他们说这是克罗斯的问题。所以,我添加了命令:

image.crossOrigin = '*';

但这对我的项目没有用。实际上,我的项目是在本地构建的,没有任何服务器。所以,我不知道为什么会出现跨域的问题。

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");
        });
};
javascript html html5-canvas
3个回答
13
投票

onload函数之外的图片需要设置

crossOrigin

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;
});

1
投票

当您加载图像时,如果它们来自其他域,它们将被标记为跨域,除非它们具有 CORS 权限。这包括从

file://
加载文件。如果使用canvas 2d,没有CORS权限的跨域图像会污染画布,如果使用WebGL则根本无法使用

如果文件位于本地,最好使用简单的服务器。 这是一个还有更多

如果图像实际上是跨域的,那么你需要通过设置

img.crossOrigin
来请求 CORS 权限,并且服务器需要返回图像的正确标头。我相信唯一需要的标题是

 Access-Control-Allow-Origin: *

您必须在设置

img.crossOrigin
之前设置
img.src
。设置
img.crossOrigin
告诉浏览器向服务器请求权限。请求会在您设置后立即发送
img.src

让我们用一个我碰巧知道支持 CORS 的 imgur URL 来尝试一下,还有你提到的你的 URL,以及我知道不支持 CORS 的我网站上的一个 URL

[
  { 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; }

我的结果,imgur 图像有效,你的有效,我的无效(如预期)

注意有8种情况

 |   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
-+-----------------+---------------+---------------+----------------------

0
投票

设置

useCORS
为ture可以解决这个问题

html2Canvas(document.querySelector('#pdfDom'), {useCORS: true}).then((canvas) => 
{
    let pageData = canvas.toDataURL('image/jpeg', 1.0);
}
© www.soinside.com 2019 - 2024. All rights reserved.