浏览器画布CORS支持跨域加载的图像操作

25

问题:哪些浏览器版本支持CORS(跨域资源共享)头部用于Canvas中使用的跨域图像

CORS可以应用于跨域XMLHttpRequest和图像请求。这个问题是关于图像请求的。我通常使用的浏览器版本兼容性http://caniuse.com/cors在这个问题上不清楚,google搜索也没有好的结果。

我找到了一篇最近Chrome开发博客文章,暗示CORS支持现代浏览器广泛使用,但由于WebGL安全问题可能会出现问题。
http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html

CORS的更多细节:

我们正在考虑使用Canvas和CORS以及W3C工作草案http://www.w3.org/TR/cors/#use-cases中描述的跨域图像请求的可行性。CORS被HTML Canvas用于允许类似Flash使用crossdomain.xml的方式来跨域使用资源。基本上,我们想要读取/编辑图像数据像素,而不想使用同源代理服务器。

通常,如果图像被跨域加载并与HTML Canvas一起使用,使用类似canvas.toDataURL()的函数访问像素会抛出安全错误。然而,如果提供图像的服务器添加了这样的头部,跨域使用应该是允许的。

access-control-allow-origin: *

我们最关注的浏览器:

我们计划通过使用Flash来解决IE缺乏Canvas支持的问题,这样对于桌面浏览器CORS问题,我们也可以采用此方法,但在移动设备上,使用Flash不是一个选择,并且在我们的情况下使用代理来进行同源请求也不可选。因此,我特别关注Andriod、Iphone和IPAD浏览器对CORS的支持。

3个回答

19

测试结果:不好的消息是,它似乎只在Chrome浏览器中可以使用。所有其他浏览器(包括安卓手机)都会出现如下错误:

Failed: DOM Exception: SECURITY_ERR (18)

移动设备 我测试了Android (三星Galaxy内核版本2.6.32.9), iPhone和iPad V1,但在这三个设备上都失败了。

您可以使用此URL测试自己的移动设备: http://maplarge.com/CrossOriginImageTest.html

测试脚本:

  <!DOCTYPE html>
<html>
<head>
<title>Canvas Cross Origin Image Test: Testing for Canvas Cross Domain Image CORS Support</title>
<script type="text/javascript">
    function initialize() {

        //will fail here if no canvas support
        try {
            var can = document.getElementById('mycanvas');
            var ctx = can.getContext('2d');
            var img = new Image();
            img.crossOrigin = '';
            //domain needs to be different from html page domain to test cross origin security
            img.src = 'http://lobbydata.com/Content/images/bg_price2.gif';
        } catch (ex) {
            document.getElementById("results").innerHTML = "<span style='color:Red;'>Failed: " + ex.Message + "</span>";
        }

        //will fail here if security error
        img.onload = function () {
            try {
                var start = new Date().getTime();
                can.width = img.width;
                can.height = img.height;
                ctx.drawImage(img, 0, 0, img.width, img.height);
                var url = can.toDataURL(); // if read succeeds, canvas isn't dirty.
                //get pixels
                var imgd = ctx.getImageData(0, 0, img.width, img.width);
                var pix = imgd.data;
                var len = pix.length;
                var argb = []; //pixels as int
                for (var i = 0; i < len; i += 4) {
                    argb.push((pix[i + 3] << 24) + (pix[i] << 16) + (pix[i + 1] << 8) + pix[i + 2]);
                }
                var end = new Date().getTime();
                var time = end - start;
                document.getElementById("results").innerHTML = "<span style='color:Green;'>" +
                "Success: Your browser supports CORS for cross domain images in Canvas <br>"+
                "Read " + argb.length+ " pixels in "+ time+"ms</span>";
            } catch (ex) {
                document.getElementById("results").innerHTML = "<span style='color:Red;'>Failed: " + ex + "</span>";
            }

        }

    }
</script>
</head>
<body onload="initialize()">
<h2>Canvas Cross Origin Image Test: Testing for Canvas Cross Domain Image CORS Support</h2>
<h2><a href="http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html">What is CORS Image Security?</a></h2>
<h1 id="results" style="color:Orange;">Testing...</h1>
<canvas id="mycanvas"></canvas>
<br />
<a href="/Example/List">More Examples</a>
</body>
</html>

2
我正要发布一个关于这个问题的问题。很高兴我不是唯一一个认为这应该可以工作的人。这在FF17中现在可以工作,但在IE10中仍然无法工作。我想我必须继续使用代理来发送我的请求。 - pseudosavant
2
1.5年后的更新:在Windows上,我刚刚测试了IE9(失败),Safari 5.0.5(失败),Firefox(通过)和Chrome(通过)。 - Glenn
它在IOS7上无法运行,因为有SVG图像! - Michael
4年后的更新:在Windows IE11(通过),Edge(通过),Firefox(通过),Chrome(通过)。 - ryanttb

3

我刚在我的iPhone上运行iOS 6,并在Safari和Chrome中进行了测试,你的测试页面通过了测试。我本来想将这个作为评论发布,但我没有发现可以给你的回答发表评论的选项。


好消息!我的帖子已经一年半了,所以我很高兴看到浏览器已经有所进步。 - Glenn
1
我在Windows 8 - IE 10上进行了测试,但仍然失败。 - bfcoder
1
已在Mac OSX 10.7.5 - Safari 6.0.2中进行测试,并且通过了。 - bfcoder
这并不是一个“答案”。可能应该与之前的类似评论一起作为评论发布。 - pseudosavant
2
@pseudosavant 如果你看了我的帖子,你就会知道我说过我不能评论。也许你已经忘记了,因为你有很高的声望,但是你必须拥有50个声望才能在任何地方发表评论。链接 在我发帖时,我没有50个声望。但是,谢谢你让我失去了2分。 - bfcoder

1

您可以使用php来获取您想要的所有内容,而不需要跨域资源共享(CROS),以下是工作示例:

<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
function a(x){
alert(x);
var img = new Image();
            img.onload = function()
            {
            var canvas = document.createElement("canvas");
            canvas.width = img.width;
            canvas.height = img.height;
            var context = canvas.getContext("2d");
            context.fillStyle = "#ffffff";
            context.fillRect(0,0,img.width,img.height);
            context.drawImage(img, 0, 0);
            var data = canvas.toDataURL('image/jpeg' , 0.8);
            document.write('<img src="'+data+'" />');
            };img.src = x;
}
</script>
<?php
$im = imagecreatefromjpeg('http://www.nasa.gov/images/content/711375main_grail20121205_4x3_946-710.jpg');
            ob_start();
            imagejpeg($im,NULL,100);
            $outputBuffer = ob_get_clean();
            $base64 = base64_encode($outputBuffer);
            $x= 'data:image/jpeg;base64,'.$base64;
            echo "<script>a('".$x."')</script>";
?>

2
这看起来像是一个代理服务。如果您控制托管页面的域并且可以添加此脚本,则应该可以正常工作。但是,在您无法控制的情况下,您将被困在处理CORS限制的境地中。对于托管可嵌入小部件或提供API服务的站点来说,这尤其痛苦,因为这意味着每个想要使用canvas触摸图像的api用户都必须设置自己特定于域的代理,以适应不正确实现CORS的浏览器。由于这个问题在许多浏览器中很常见,所以不能忽视它。 - Glenn
1
最重要的是将base64解码后的图像放入画布中,以避免CORS限制。在API服务中,也可以向客户提供base64解码后的图像,而不是图像URL。 - varoniic
如果您的文件大小不超过32KB,甚至可以获得IE8支持。我对文本转换膨胀和解码性能很感兴趣。您是否对此进行了任何统计?这位专家认为膨胀可能相当大http://appcropolis.com/javascript-encode-images-dataurl/。 - Glenn

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