Dimitar Dakovski
Dimitar Dakovski

Reputation: 69

HTML 5 canvas getImageData from an externally-loaded image

I know it is not possible to do it straightaway due to security reasons. However, I have heard there are some image-hosting websites that allow their images to be used in a similar manner (Google Picasa?). I could be all wrong, but I would like to know if this is true and if so, how can I get image data from such an image.

Thank you in advance.

Upvotes: 3

Views: 8156

Answers (1)

markE
markE

Reputation: 105015

Yes, there are public hosts that serve images that can be used in canvas’ getImageData

Dropbox is one of them: http://www.dropbox.com

To use those images, you must use the context.crossOrigin=’anonymous’ flag when loading the image:

var image=document.createElement("img");  // Chrome bug prevents var image=new Image();
image.onload=function(){

        // in Chrome+Mozilla you can use context.getImageData

        // but IE still throws the CORS security error

}
image.crossOrigin = "Anonymous";
image.src="www.CrossOriginSite.com/anyImage.png";

One remaining "Gotcha" is that the IE browser still does not honor the crossOrigin flag, so IE still will not let you use these images with getImageData.

Chrome and Mozilla allow getImageData access.

For example...

This Fiddle will succeed when viewed in Chrome or Mozilla, but will still fail in IE:

http://jsfiddle.net/m1erickson/czmms/

Here is code:

<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var canvasCORS=document.getElementById("canvasCORS");
    var ctxCORS=canvasCORS.getContext("2d");
    var canvasAnonymous=document.getElementById("canvasAnonymous");
    var ctxAnonymous=canvasAnonymous.getContext("2d");

    // Using image WITHOUT crossOrigin=anonymous
    // Fails in all browsers
    var externalImage1=document.createElement("img");  // chrome bug prevents new Image();
    externalImage1.onload=function(){
        canvas.width=externalImage1.width;
        canvas.height=externalImage1.height;
        ctx.drawImage(externalImage1,0,0);
        // use getImageData to replace blue with yellow
        var imageData=recolorImage(externalImage1,0,0,255,255,255,0);
        // put the altered data back on the canvas  
        // this will FAIL on a CORS violation
        ctxCORS.putImageData(imageData,0,0);    
    }
    externalImage1.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";

    // Using image WITH crossOrigin=anonymous
    // Succeeds in Chrome+Mozilla, Still fails in IE
    var externalImage2=new Image();
    externalImage2.onload=function(){
        canvas.width=externalImage2.width;
        canvas.height=externalImage2.height;
        ctx.drawImage(externalImage2,0,0);
        // use getImageData to replace blue with yellow
        var imageData=recolorImage(externalImage2,0,0,255,255,255,0);
        // put the altered data back on the canvas  
        // this will FAIL on a CORS violation
        ctxAnonymous.putImageData(imageData,0,0);    
    }
    externalImage2.crossOrigin = "Anonymous";
    externalImage2.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";


    function recolorImage(img,oldRed,oldGreen,oldBlue,newRed,newGreen,newBlue){
        var c = document.createElement('canvas');
        var ctx=c.getContext("2d");
        var w = img.width;
        var h = img.height;
        c.width = w;
        c.height = h;

        // draw the image on the temporary canvas
        ctx.drawImage(img, 0, 0, w, h);

        // pull the entire image into an array of pixel data
        var imageData = ctx.getImageData(0, 0, w, h);

        // examine every pixel, 
        // change any old rgb to the new-rgb
        for (var i=0;i<imageData.data.length;i+=4)
          {
              // is this pixel the old rgb?
              if(imageData.data[i]==oldRed &&
                 imageData.data[i+1]==oldGreen &&
                 imageData.data[i+2]==oldBlue
              ){
                  // change to your new rgb
                  imageData.data[i]=newRed;
                  imageData.data[i+1]=newGreen;
                  imageData.data[i+2]=newBlue;
              }
          }
        return(imageData);
    }


}); // end $(function(){});
</script>

</head>

<body>
    <p>Original external image</p>
    <canvas id="canvas" width=140 height=140></canvas>
    <p>.getImageData with .crossOrigin='anonymous'
    <p>[Succeeds in Chrome+Mozilla, still fails in IE]</p>
    <canvas id="canvasAnonymous" width=140 height=140></canvas>
    <p>.getImageData without .crossOrigin='anonymous'
    <p>[Fails on all browsers]</p>
    <canvas id="canvasCORS" width=140 height=140></canvas>
</body>
</html>

Upvotes: 9

Related Questions