1

Working on a react component where I have the following in my render():

<img id="map_image" src={this.state.last_parking.url} />

this.state.last_parking.url is simply some url I'm saving in my local state.

I want the value of the rgba colors in this image. So I made a function like this which uses my img element through id map_image:

showData = async (url, x, y) => {
            let image_ = document.getElementById("map_image")
            image_.crossOrigin = "Anonymous"
            let canvas = document.createElement('canvas');
            let context = canvas.getContext('2d');

            context.drawImage(image_, 0, 0, 100, 100)
            let data = await context.getImageData(0, 0, 50, 50).data
            console.log(data)
        }

Unfortunately, what I see in the console is some sort of Uint8ClampedArray where every single value is 0. Honestly, I just want the rgba values in the very center of the image. How can I make my getImageData array have actual rgba values?

Edit: I originally used this simple function: https://coderwall.com/p/iyhizq/get-the-pixel-data-of-an-image-in-html But it also returns just 0's

2 Answers2

2

Please try this:

showData = (url, x, y) => {
  let image_ = document.getElementById('map_image')
  image_.crossOrigin = 'Anonymous'
  let canvas = document.createElement('canvas');
  let context = canvas.getContext('2d');
  return Promise((resolve) => {
    image_.onLoad = () => {
      context.drawImage(image_, 0, 0, 100, 100);
      let data = context.getImageData(0, 0, 50, 50).data;
      console.log(data);
      resolve(data);
    };
  });
};

(Code modified per kshetline's suggestion to support returning the data via promise.)

see sharper
  • 11,505
  • 8
  • 46
  • 65
  • Yes, OK so both of your codes, after some minor modification for my particular circumstances, work fine. I guess the central idea I was missing was using asynchronous Promise based technique on getImageData. That was actually the whole issue. I think I've got to review how to implement Promises to force synchronous behavior for this and future issues. Thanks a ton! – Mahdiur Rahman Jan 23 '20 at 01:03
  • You're welcome - upvote and/or mark as answer appreciated. – see sharper Jan 23 '20 at 01:05
  • 1
    I can't :( my reputation is too low. I upvoted both of you guys it just won't show. – Mahdiur Rahman Jan 23 '20 at 01:09
2

You need to wait for the image to load before you draw, otherwise you're likely not to get anything. Just as I was writing this answer, someone else posted code that'll put you on the right track, it just needs to be modified a bit to handle the onload function as a Promise if you want to stick to the async function paradigm.

Update: Here's the code in async form:

showData = async (url, x, y) => {
            let image_ = document.getElementById("map_image")
            image_.crossOrigin = "Anonymous"

            await new Promise((resolve, reject) => {
              image_.onload = () => resolve()
              image_.onerror = err => reject(err)
            })

            let canvas = document.createElement('canvas');
            let context = canvas.getContext('2d');

            context.drawImage(image_, 0, 0, 100, 100)
            // No await here -- this method is synchronous
            let data = context.getImageData(0, 0, 50, 50).data
            console.log(data)
        }
kshetline
  • 12,547
  • 4
  • 37
  • 73