CanvasContext2D drawImage() 问题 [onload 和 CORS]

CanvasContext2D drawImage() issue [onload and CORS]

我试图在 canvas 上绘制图像,然后再获取它的 dataURL(),但返回的数据就像是空的。

当我在控制台中查看时,我看到字符串中有很多 A : ("data:image/png;base64,iVBO..some random chars... bQhfoAAAAAAAAAA... a lot of A ...AAAASUVORK5CYII=")

当我尝试将 canvas 附加到文档时,也没有绘制任何内容,控制台中也没有抛出任何错误。

这里有什么问题?

这是我的代码:

var img = new Image();
img.src = "http://somerandomWebsite/picture.png";
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0,0); // this doesn't seem to work
var dataURL = canvas.toDataURL(); // this will give me a lot of "A"    
doSomething(dataURL);

此外,在进行快速刷新时,图像会正确地绘制到 canvas 上,但我在控制台中收到一条错误消息并且 dataURL 是空的。

Firefox 中的消息是:"SecurityError: The operation is insecure.",
在 Chrome 中是 "Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
在 IE 上我只得到 "SecurityError"

这是什么意思?

您必须等待图像 加载 才能在 canvas 上绘画。

为此,只需使用 <img> 元素的 load 事件处理程序:

// create a new image
var img = new Image();
// declare a function to call once the image has loaded
img.onload = function(){
  var canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  var context = canvas.getContext('2d');
  context.drawImage(img, 0,0);
  var dataURL = canvas.toDataURL();
  // now you can do something with the dataURL
  doSomething(dataURL);
}
// now set the image's src
img.src = "http://somerandomWebsite/picture.png";

此外,为了 canvas' context.toDataURL()context.getImageData 正常工作,您必须在 cross-origin compliant way 中获取图像资源,否则 canvas 是 "tainted" 这意味着任何获取像素数据的方法都将被阻止。

  • 如果您的图像来自同一 服务器,没问题。
  • 如果您的图像是从 外部服务器 提供的,请确保它在其 cross-origin header 中允许您的图像并设置 img.crossOrigin"use-credentials"
  • 如果服务器允许匿名请求,您可以将img.crossOrigin设置为"anonymous"

Nota Bene : CORS header 由服务器发送, cross-origin属性只会让它知道你想使用 CORS 来获取图像数据,如果服务器设置不正确,你无法绕过它。
还有一些 UserAgents(IE 和 Safari)还没有实现这个属性。

Edge Case :如果您的某些图像来自您的服务器,而另一些来自符合 CORS 标准的图像,那么您可能需要使用 onerror 事件处理程序如果您在非 CORS 服务器上将 cross-origin 属性设置为 "anonymous",这应该触发。

function corsError(){
  this.crossOrigin='';
  this.src='';
  this.removeEventListener('error', corsError, false);
} 
img.addEventListener('error', corsError, false);