CanvasContext2D drawImage()问题[关于onload和CORS]

8

我正在尝试在获取dataURL()之前,在画布上绘制图像,但是返回的数据似乎是空的。

当我在控制台中检查它时,我看到字符串中有很多A"data:image/png;base64,iVBO..随机字符... bQhfoAAAAAAAAAA...很多个A...AAAASUVORK5CYII="

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

问题出在哪里?

这是我的代码:

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

在进行快速刷新时,图像被正确地绘制到画布上,但是我在控制台中收到了一条错误消息,dataURL为空。

在Firefox中,出现以下消息:"SecurityError: 操作不安全。"
在Chrome中,出现以下消息:"Uncaught SecurityError: 无法对带有污染的画布执行'toDataURL'。",
而在IE中,我只看到了"SecurityError"

这是什么意思?


这篇文章旨在成为我们每周收到的20多个关于此特定问题的标准文章。如果可以改进,请告诉我。 - Kaiido
加载图像后再进行任何操作不是更重要吗?如果您认为引用toDataURL很有用,那么应该提到(可能存在的)CORS问题。无论如何,对于维基百科的想法/努力+1。 - GameAlchemist
@GameAlchemist 你说得对,我试图将两个问题结合起来,因为它们非常相似并且经常成对出现。我在回答中谈到了CORS问题。不知道搜索引擎会如何处理,也许我应该将“画布被污染”消息错误添加到问题中。无论如何,我还要求将问题转换为wiki,这样,您就可以编辑它了。 - Kaiido
1个回答

8
你必须等待图像加载完成后才能在画布上绘制它。为此,只需使用<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";

此外,为了让画布的context.toDataURL()context.getImageData正常工作,您必须以跨源兼容方式获取图像资源,否则画布会被“污染”,这意味着任何获取像素数据的方法都将被阻止。
  • 如果您的图像来自同一服务器,那就没有问题。
  • 如果您的图像来自外部服务器,请确保它在其跨源标头中允许您的服务器,并将img.crossOrigin设置为"use-credentials"
  • 如果服务器允许匿名请求,则可以将img.crossOrigin设置为"anonymous"
Nota BeneCORS 头信息由服务器发送cross-origin 属性仅告诉服务器您想使用 CORS 获取图像数据,如果服务器未正确设置,则无法绕过它。
此外,一些 UserAgents(IE 和 Safari)仍未实现此属性。 边缘情况:如果您的一些图像来自您的服务器,而另一些图像来自符合CORS标准的服务器,则可能需要使用 onerror 事件处理程序。如果在非CORS服务器上将 cross-origin 属性设置为 "anonymous",则应该触发该事件。
function corsError(){
  this.crossOrigin='';
  this.src='';
  this.removeEventListener('error', corsError, false);
} 
img.addEventListener('error', corsError, false);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接