12

I'm trying to output the pixel values from an image. The image is loading correctly; another answer on here suggested that the browswer is trying to read the pixels before the image is finished loading, but I can see that it's loaded by the time the alert() fires.

function initContext(canvasID, contextType)
{
   var canvas = document.getElementById(canvasID);
   var context = canvas.getContext(contextType);
   return context;
}

function loadImage(imageSource, context)
{
    var imageObj = new Image();
    imageObj.onload = function()
    {
        context.drawImage(imageObj, 0, 0);
    };
    imageObj.src = imageSource;
    return imageObj;
}

function readImage(imageData)
{
    console.log();
    console.log(imageData.data[0]);
}

var context = initContext('canvas','2d');
var imageObj = loadImage('images/color-test.png',context);
var imageData = context.getImageData(0,0,10,10);
alert();
readImage(imageData);
zzxjoanw
  • 374
  • 4
  • 16
  • 1
    "loaded by the time the alert() fires" doesn't mean "loaded by the time `getImageData()` is called" – Paul Roub Aug 28 '15 at 20:32
  • I moved the alert() to before the getImageData() call (Thanks, Paul!) and now it works. So it needed more time to load, I guess - only the accepted answer [here](http://stackoverflow.com/questions/5694599/getimagedata-always-returning-0) says to use an onload function to deal with that, and that's what I had. I'm not sure why it wasn't working. – zzxjoanw Aug 28 '15 at 20:37
  • 1
    You're calling `onload`, but not waiting for it to run. You're best off calling `getImageData()` and `readImage()` *from* the `onload` handler, to be sure it's done. Otherwise you're doomed once you remove the `alert()`. – Paul Roub Aug 28 '15 at 20:39

3 Answers3

13

Image.onload() is called asynchronously when the image has been loaded. That can happen after your current code calls context.getImageData().

The following code should work:

function initContext(canvasID, contextType)
{
   var canvas = document.getElementById(canvasID);
   var context = canvas.getContext(contextType);
   return context;
}

function loadImage(imageSource, context)
{
    var imageObj = new Image();
    imageObj.onload = function()
    {
        context.drawImage(imageObj, 0, 0);
        var imageData = context.getImageData(0,0,10,10);
        readImage(imageData);
    };
    imageObj.src = imageSource;
    return imageObj;
}

function readImage(imageData)
{
    console.log();
    console.log(imageData.data[0]);
}

var context = initContext('canvas','2d');
var imageObj = loadImage('images/color-test.png',context);

If you want to access the imageData value outside of loadImage(), you have 2 basic choices:

  1. Store the imageData in a variable that is declared outside the function. In this case, the value will be unset until your onload() is called, so the outside code would have to test it for reasonableness before calling readImage(imageData).
  2. Have the outside code register a callback function, and have your onload() call that function with the imageData value.
cybersam
  • 63,203
  • 6
  • 53
  • 76
3

It is also possible you are evaluating a portion of an image that is transparent. I had this issue while scanning a PNG.

Apocalypse
  • 69
  • 5
0

Share a situation I encountered when I used a loop to request multiple images at the same time and get their pixels respectively. Then I encountered this problem.

//my code looks like this
for(let i = 0; i < urls.length; ++i){
    let img = new Image() // it will be destoryed every loop begin, even if use keyword 'var' insteads of 'let'.  
    img.onload = ()=>{
      let canvas = document.createElement('canvas')
      let ctx = canvas.getContext('2d')
      ctx.drawImage(img, 0, 0)
      let imgData = ctx.getImageData(0, 0, 1024, 1024) // imgData will be all 0 or some other unexpected result.
    }
    img.src = urls[i]
}

// fixed bug
window.imgs = []
for(let i = 0; i < urls.length; ++i)
    window.imgs[i] = new Image()
for(let i = 0; i < urls.length; ++i){
    let img = window.imgs[i]
    img.onload = ()=>{
      let canvas = document.createElement('canvas')
      let ctx = canvas.getContext('2d')
      ctx.drawImage(img, 0, 0)
      let imgData = ctx.getImageData(0, 0, 1024, 1024) 
    }
    img.src = urls[i]
}

The reason may be object reference, garbage collection and other problems. I don't know. Because I'm a beginner of js.

liningx
  • 11
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 21 '22 at 11:18
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/31589283) – Zach Jensz Apr 26 '22 at 03:05