1

I'm trying to read image data through the canvas tag and every time I try to retrieve and display that data it all comes up 0's. Even if I limit the data grab to 1 pixel it comes up "0, 0, 0, 0". The odd thing is that I can use fillRect and retrieve that data, but when drawing an image it comes up zeros. I'll be using this script to compare pixels to find out if the pattern is repeatable, but first I need to make sure I can read that data in the first place.

Below is my code. I'm sort of old fashion and use a text editor and browser to test with. As a result, I don't have this up on any WYSIWYG editors that some people use. You'll just have to use an image and change the source to get it to work locally. Though I could set it up elsewhere if requested.

I hope I can get some insight as to why this isn't working.

    <!DOCTYPE HTML>
    <html>
        <head>
            <style type="text/css">
                body { background-color:#dedddd }
                canvas { background-color:white; padding:20px }
                #colorInfo { width:300px; background-color:white; padding:20px }
            </style>
        </head>
        <body>
            <canvas id="iLikeCookies" width="300" height="300">Your browser kinda sucks.  Can't even draw a canvas.  For shame.</canvas>
            <div id="header"></div>
            <div id="colorInfo"></div>
            <script>
                var canvas = document.getElementById('iLikeCookies');
                var ctx = canvas.getContext('2d');
                var img = new Image();
                pixelData = '';

                // function to read all pixels and build into string of RGBa values.
                var read = function() {
                    // loop through each row
                    for(var y = 0; y < canvas.height; y++) {
                        // loop through each column
                        for(var x = 0; x < canvas.width; x++) {
                            // grabbing individual pixel data
                            var red = pixels[((canvas.width * y) + x) * 4];
                            var green = pixels[((canvas.width * y) + x) * 4 + 1];
                            var blue = pixels[((canvas.width * y) + x) * 4 + 2];
                            var alpha = pixels[((canvas.width * y) + x) * 4 + 3];
                            // adding current pixel data to string
                            pixelData += "RGBa(" + red + ", " + green + ", " + blue + ", " + alpha + ") <br/>";
                        }
                    }
                };

                img.onload = function() {   
                    ctx.drawImage(img, 0, 0, 300, 300);
                };

                // ctx.fillStyle = "rgb(123,40,170)"
                // ctx.fillRect(0,0,300,300)
                img.src = 'pattern2.jpg';
                imgData = ctx.getImageData(0, 0, canvas.width-299, canvas.height-299);
                pixels = imgData.data           
                read();
                console.log(img.width + ", " + img.height);
                document.getElementById("header").innerHTML = "Here are the " + canvas.height*canvas.width + " pixels found in the image.<br/>";                
                document.getElementById("colorInfo").innerHTML = pixelData;
                console.log(pixelData);

            </script>
        </body>
    </html>
Peter O.
  • 32,158
  • 14
  • 82
  • 96
aphero
  • 11
  • 2
  • See here for satisfying cross-origin requirements so you don't get the security errors: http://enable-cors.org/ – markE Jul 26 '15 at 21:09

1 Answers1

0

Put your code starting with imgData = … inside your img.onload function and set img.crossOrigin = 'anonymous'; to get rid of the SecurityError:

img.crossOrigin = 'anonymous';
img.src = 'pattern2.jpg';
img.onload = function() {
  ctx.drawImage(img, 0, 0, 300, 300);

  // ctx.fillStyle = "rgb(123,40,170)"
  // ctx.fillRect(0,0,300,300)

  imgData = ctx.getImageData(0, 0, canvas.width - 299, canvas.height - 299);
  pixels = imgData.data
  read();
  console.log(img.width + ", " + img.height);
  document.getElementById("header").innerHTML = "Here are the " + canvas.height * canvas.width + " pixels found in the image.<br/>";
  document.getElementById("colorInfo").innerHTML = pixelData;
  console.log(pixelData);
};
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
  • When doing that it throws the following into console: Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data. – aphero Jul 26 '15 at 19:33
  • See the edit: `img.crossOrigin = 'anonymous';` should fix that. – Sebastian Simon Jul 26 '15 at 19:35
  • Now getting: Image from origin 'file://' has been blocked from loading by Cross-Origin Resource Sharing policy: Received an invalid response. Origin 'null' is therefore not allowed access. – aphero Jul 26 '15 at 19:40
  • Using Chrome 43.0.2357.134 by the way – aphero Jul 26 '15 at 19:43
  • You could try it from a server. At least you’ve got the event listener right with `onload`. [Research this problem yourself, seperately](http://stackoverflow.com/questions/8018118), or ask a new question if you can’t find anything helpful. – Sebastian Simon Jul 26 '15 at 19:44
  • 1
    I appreciate the guidance. I'll look into trying from a server and figuring out what's causing the error and report back. – aphero Jul 26 '15 at 19:52
  • 1
    @Xufox. By default, loading an image from a domain other than the webpage's domain with taint the canvas. Tainting the canvas automatically disables `context.getImageData`. Setting `img.crossOrigin` *without also configuring the other-domain image server to deliver its images anonymously* will not satisfy cross-origin restrictions and the canvas will still become tainted. ;-) – markE Jul 26 '15 at 21:03
  • 1
    Installed MAMP and ran the script and it works! I'm going to study more on this so I can better understand it, but at least I can continue working on my script now. Many, many thanks @Xufox for clearing up my problem! And thanks for adding some extra info @markE! – aphero Jul 27 '15 at 17:32