Browser Canvas CORS Support for Cross Domain Loaded Image Manipulation

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.


Solution 1:

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>

Solution 2:

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.

Solution 3:

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>";
?>