25

QUESTION: What browser versions support CORS (Cross-Origin Resource Sharing) headers for Cross Domain Images used in Canvas?

CORS can apply to both cross domain XMLHttpRequests and to image requests. This question is about image requests My normal go to for browser version compatibility http://caniuse.com/cors is unclear on the issue and google search yields no good results.

I did find a recent chrome development blog implying that CORS support was wide spread in modern browsers but might break because of WebGL security problems.
http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html

More detail on CORS:

We're considering the viability of using canvas & CORS with cross domain image requests as described in the W3C Working Draft http://www.w3.org/TR/cors/#use-cases. CORS is used by html canvas to allow cross domain resource usage in a fashion similar to the way flash uses crossdomain.xml. Basically, we want to read/edit the image data pixels and we don't want to use a same origin proxy server.

Normally, if are images loaded cross domain and used with html canvas, accessing pixels using functions like canvas.toDataURL() will throw a security error. However, If the server delivering the image adds a header like this, the cross domain usage should be allowed.

access-control-allow-origin: *

Browsers We Care Most About:

We are planning to work around IE's lack of canvas support using flash, so for desktop browsers with a CORS problem we can do that as well, but on mobile flash is not an option, and using a proxy to make the requests same origin is not an option in our use case. So, I'm particularly interested in Andriod, Iphone, IPAD browser support for CORS.

Glenn
  • 1,234
  • 2
  • 19
  • 33

3 Answers3

19

Test Results: Bad News, it appears to only work in Chrome. All other browsers (including Android Mobile) give an error like this:

Failed: DOM Exception: SECURITY_ERR (18)

Mobile Devices I tested Android (samsung galaxy kernel version 2.6.32.9), Iphone and IPAD V1 and it failed in all three.

You can test your own mobile device with this URL: http://maplarge.com/CrossOriginImageTest.html

The Test Script:

  <!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>
Glenn
  • 1,234
  • 2
  • 19
  • 33
  • 2
    I was just about to post a question about this. Glad I'm not the only one going crazy thinking this *should* work. This now works in FF17, but still doesn't work in IE10. Guess I'll have to keep using a proxy for my requests. – pseudosavant Dec 10 '12 at 21:45
  • 2
    Update 1.5 years later: On Windows I just tested IE9 (fail), Safari 5.0.5 (fail), Firefox (pass) and Chrome (pass) – Glenn Dec 28 '12 at 21:28
  • It doesn't run on IOS7 with SVG image! – Michael May 21 '14 at 14:45
  • Update 4 years later: On Windows IE11 (pass), Edge (pass), Firefox (pass), Chrome (pass). – ryanttb Aug 22 '15 at 17:10
3

I just tested this on my iPhone running iOS 6 in both Safari and in Chrome and your test page passes the test. I would have posted this as a comment but I am not given the option to post a comment to your answer.

bfcoder
  • 3,042
  • 2
  • 28
  • 35
  • Great news! My post is a year and half old so I'm glad to see browsers have progressed. – Glenn Dec 28 '12 at 21:20
  • 1
    I tested in Windows 8 - IE 10 and it still fails. – bfcoder Dec 29 '12 at 15:05
  • 1
    tested in Mac OSX 10.7.5 - Safari 6.0.2 and it passes. – bfcoder Dec 29 '12 at 15:06
  • Not really an 'answer'. Probably should have just been a comment along with the prior answer with similar comments. – pseudosavant Jan 07 '13 at 21:03
  • 2
    @pseudosavant if you read my post you would have seen that I stated I could not comment. Maybe you have forgotten since you have a lot of reputation, but you have to have 50 rep to comment everywhere. [link](http://stackoverflow.com/privileges/comment) At the time of my post, I did not have 50 rep. But hey, thanks for making me loose 2 points.. – bfcoder Jan 08 '13 at 01:02
1

You could use php to get all what you want without CROS, working example below:

<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>";
?>
varoniic
  • 11
  • 1
  • 2
    This looks like a proxy service. If you control the domain hosting the page and can add this script, it should work. However, in cases where you don't then you're stuck dealing with the limitations of CORS. This is particularly painful for sites that host embeddable widgets or provide api services, because it means that every user of the api who wants to touch images with canvas has to setup their own domain specific proxy if they want to accommodate browsers that don't properly implement CORS. Because the problem is common in many browsers it can't be ignored. – Glenn Jan 08 '13 at 19:17
  • 1
    The main thing is to get base64 decoded image to canvas becouse of no CORS limitations. And in API services also is possible to give to clients base64 decoded image instead of image URL. – varoniic Jan 09 '13 at 12:41
  • If you're under 32KB you can even get IE8 support. I'm curious about the text conversion bloat and decoding performance. Have you run any stats on this? This guy suggests the bloat can be quite large http://appcropolis.com/javascript-encode-images-dataurl/ – Glenn Jan 10 '13 at 17:39