Canvas.toDataURL()在除了IE10以外的所有浏览器中都有效。

13

我正在开发一个项目,使用画布自动裁剪图片,然后返回其数据URL。它使用来自外部服务器的图像,该服务器具有适当的CORS标头,即使这些图像是跨域的,在它们被裁剪后也可以将它们转换为数据URI。

代码在所有浏览器中都完美运作(且没有安全错误!),唯独在IE 10中出现问题,当调用canvas.toDataURL()时会抛出'SCRIPT5022: SecurityError'。

这是IE的一个bug还是我需要在我的代码中做出不同的调整才能使其在"白痴浏览器"中工作?谢谢。 -Scott

编辑 这里是我用于创建和绘制画布的代码的大部分内容;

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = imageServerURL + '?id=' + imageIdToGet; // imageServerURL points to a different domain but the server has headers allowing requests from my domain
/*
    code here that defines the cropping area, in variables like ulX, lrY, etc.
*/
ctx.beginPath();
ctx.moveTo(ulX, ulY);
ctx.lineTo(urX, urY);
ctx.lineTo(lrX, lrY);
ctx.lineTo(llX, llY);
ctx.closePath();
ctx.clip();
ctx.drawImage(img, 0, 0);
var url = canvas.toDataURL(); // This succeeds in all other browsers but throws a SecurityError in IE

首先,展示你的代码并/或解释一下这个画布是如何创建的以及它包含了什么。 - Ray Nicholus
原问题已编辑。 - Scott Odle
2个回答

20

不幸的是,即使CORS标头已经设置正确,IE10仍然是唯一不支持Canvas绘制的图像的CORS的流行浏览器。但是,可以通过XMLHttpRequest绕过这个问题,甚至无需在服务器端代理图像:

var xhr = new XMLHttpRequest();
xhr.onload = function () {
    var url = URL.createObjectURL(this.response);
    img.src = url;

    // here you can use img for drawing to canvas and handling

    // don't forget to free memory up when you're done (you can do this as soon as image is drawn to canvas)
    URL.revokeObjectURL(url);
};
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.send();

3
我正在使用fabricJS,并且在IE中遇到了相同的问题。与您的示例唯一的差别是,在图像加载完成之前撤销ObjectURL img.onload = function(e) { ... }。您可以在此处找到完整的示例:http://www.html5rocks.com/en/tutorials/file/xhr2/#toc-reponseTypeBlob - mbenegas
10
当 URL 是数据 URI(data:image/svg+xml;base64,...)时,这种方法不起作用。 - vbarbarosh
1
@vbarbarosh 当它是数据URI时,它与这个关于CORS的问题完全无关。 - RReverser
6
@rreverser,我们通过搜索“todataurl在ie10中无法工作”找到了这篇文章。虽然这不是最初提出的问题,但似乎如果您在IE10中将一个base64编码的图像加载到画布中,那么它会污染画布,您将无法再调用canvas的toDataUrl方法。 - agrath
1
@agrath 嗯,是的,那不是最初提出的问题,而是一种旨在限制安全性的措施。 - RReverser
显示剩余2条评论

6
我不相信IE10支持跨域资源共享(CORS)来使用图片。这篇MDN文章似乎证实了这一点。
正如文章所述:
尽管您可以在canvas中使用未经CORS批准的图像,但这会污染画布。一旦画布被污染,您就无法再从画布中取回数据。例如,您不能再使用canvas.toBlob()、canvas.toDataURL()或canvas.getImageData()方法;否则将抛出安全错误。
因此,看起来你需要在尝试这样做之前从与托管代码相同的来源/域代理图像,至少对于IE10和Opera浏览器来说是这样的。
为了解决不支持图片跨域资源共享的浏览器,您需要通过服务器代理图像。您可以通过将图像源发送到本地服务器上的已知端点,并将图像的源URL作为查询参数传递来轻松完成此操作。
例如:
var sourceImageUrl = "https://www.google.com/images/srpr/logo4w.png",  
    localProxyEndpoint = "/imageproxy",   
    image = new Image();   

image.src = localProxyEndpoint + "?source=" + encodeURIComponent(sourceImageUrl);

现在,在服务器端,您将处理此GET请求,从URI中剥离source参数的值,从源中获取图像,并在响应中返回它。


它在Windows 8上的Opera 15中按预期工作。这个“代理”解决方案包括什么? - Scott Odle
可能在Opera 15中可以工作,因为该版本的Opera是基于Chromium构建的。稍后我会编辑我的答案并提供更多细节。 - Ray Nicholus

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