Browser Canvas CORS Support for Cross Domain Loaded Image Manipulation

14,883

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>";
?>
Share:
14,883

Related videos on Youtube

Glenn
Author by

Glenn

At MapLarge.com make high performance, interactive web maps for Media and Business applications.

Updated on June 04, 2022

Comments

  • Glenn
    Glenn almost 2 years

    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.

  • pseudosavant
    pseudosavant over 11 years
    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.
  • Glenn
    Glenn over 11 years
    Great news! My post is a year and half old so I'm glad to see browsers have progressed.
  • Glenn
    Glenn over 11 years
    Update 1.5 years later: On Windows I just tested IE9 (fail), Safari 5.0.5 (fail), Firefox (pass) and Chrome (pass)
  • bfcoder
    bfcoder over 11 years
    I tested in Windows 8 - IE 10 and it still fails.
  • bfcoder
    bfcoder over 11 years
    tested in Mac OSX 10.7.5 - Safari 6.0.2 and it passes.
  • pseudosavant
    pseudosavant over 11 years
    Not really an 'answer'. Probably should have just been a comment along with the prior answer with similar comments.
  • bfcoder
    bfcoder over 11 years
    @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 At the time of my post, I did not have 50 rep. But hey, thanks for making me loose 2 points..
  • Glenn
    Glenn over 11 years
    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.
  • varoniic
    varoniic over 11 years
    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.
  • Glenn
    Glenn over 11 years
    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 appcropolis.com/javascript-encode-images-dataurl
  • confile
    confile almost 10 years
    It doesn't run on IOS7 with SVG image!
  • ryanttb
    ryanttb over 8 years
    Update 4 years later: On Windows IE11 (pass), Edge (pass), Firefox (pass), Chrome (pass).