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

Posted

技术标签:

【中文标题】浏览器画布 CORS 支持跨域加载图像操作【英文标题】:Browser Canvas CORS Support for Cross Domain Loaded Image Manipulation 【发布时间】:2011-10-31 01:06:56 【问题描述】:

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

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

我确实发现最近的 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 中所述。 html canvas 使用 CORS 允许以类似于 flash 使用 crossdomain.xml 的方式使用跨域资源。基本上,我们想要读取/编辑图像数据像素并且我们不想使用同源代理服务器。

通常,如果图像是跨域加载并与 html canvas 一起使用,则使用 canvas.toDataURL() 等函数访问像素将引发安全错误。但是,如果提供图片的服务器添加这样的header,应该允许跨域使用。

access-control-allow-origin: *

我们最关心的浏览器:

我们计划使用 flash 解决 IE 缺乏画布支持的问题,因此对于有 CORS 问题的桌面浏览器,我们也可以这样做,但在移动 flash 上不是一个选项,并且使用代理来使请求相同在我们的用例中,origin 不是一个选项。所以,我对 android、Iphone、IPAD 浏览器对 CORS 的支持特别感兴趣。

【问题讨论】:

【参考方案1】:

测试结果:坏消息,它似乎只适用于 Chrome。 所有其他浏览器(包括 Android Mobile)都会出现这样的错误:

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>

【讨论】:

我正要发布一个关于此的问题。很高兴我不是唯一一个认为这应该有效的人。这现在在 FF17 中有效,但在 IE10 中仍然无效。我想我将不得不继续使用代理来处理我的请求。 1.5 年后更新:在 Windows 上我刚刚测试了 IE9(失败)、Safari 5.0.5(失败)、Firefox(通过)和 Chrome(通过) 它不能在带有 SVG 图像的 ios7 上运行! 4 年后更新:Windows IE11(通过)、Edge(通过)、Firefox(通过)、Chrome(通过)。【参考方案2】:

我刚刚在 Safari 和 Chrome 中运行 iOS 6 的 iPhone 上对此进行了测试,您的测试页面通过了测试。我会将此作为评论发布,但我无法选择对您的答案发表评论。

【讨论】:

好消息!我的帖子已经发布一年半了,所以我很高兴看到浏览器取得了进步。 我在 Windows 8 - IE 10 中测试过,但仍然失败。 在 Mac OSX 10.7.5 - Safari 6.0.2 中测试并通过。 不是真正的“答案”。可能应该只是一个评论以及类似 cmets 的先前答案。 @pseudosavant 如果您阅读我的帖子,您会看到我说我无法发表评论。也许你已经忘记了,因为你有很多声誉,但你必须有 50 个代表才能在任何地方发表评论。 link 在我发帖时,我没有 50 个代表。但是,嘿,谢谢你让我失去 2 分..【参考方案3】:

您可以使用 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>";
?>

【讨论】:

这看起来像一个代理服务。如果您控制托管页面的域并且可以添加此脚本,它应该可以工作。但是,如果您不这样做,那么您将不得不处理 CORS 的限制。这对于托管可嵌入小部件或提供 api 服务的站点来说尤其痛苦,因为这意味着每个想要使用画布触摸图像的 api 用户如果想要适应不正确的浏览器,就必须设置自己的域特定代理实施 CORS。因为这个问题在很多浏览器中都很常见,所以不能忽视。 主要是将base64解码的图像获取到画布,因为没有CORS限制。并且在 API 服务中也可以将 base64 解码图像而不是图像 URL 提供给客户端。 如果您小于 32KB,您甚至可以获得 IE8 支持。我对文本转换膨胀和解码​​性能很好奇。你有没有对此进行任何统计?这家伙建议膨胀可能相当大appcropolis.com/javascript-encode-images-dataurl

以上是关于浏览器画布 CORS 支持跨域加载图像操作的主要内容,如果未能解决你的问题,请参考以下文章

画布中图像的 CORS 设置

Javascript CORS 图像/画布操作

从浏览器缓存提供图像时,AWS S3 + CloudFront 会出现 CORS 错误

跨域 JSONP, CORS

什么可以解释浏览器间歇性地不加载某些 CORS(跨域)javascript 文件?

cors解决跨域