getImageData not the same after run through createImageBitmap

396 views Asked by At

I have a function which downloads an image, and saves the image data. Based on user preference, it can save the image data in one of two ways - as an ImageData Uint8ClampedArray, or as an ImageBitmap. I'm using an image loading function to wait until the image is loaded before running my save function:

function loadImage(src) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.crossOrigin = '*';
        img.addEventListener('load', () => resolve(img));
        img.src = src;
    });
}

The function which saves the image data is this:

async function fetchAndSaveImage(priority) {
  const imageUrl = `some_url`;

  // Create a canvas, so I can write the image data to it and then call getImageData on it
  var transferCanvas = document.createElement('canvas');
  transferCanvas.width = transferCanvas.height = 256;
  var c = transferCanvas.getContext('2d');

  await loadImage(imageUrl).then((image) => {
    if (priority === 'speed') {
      c.drawImage(image, 0, 0, 256, 256);
      var pixelData = c.getImageData(0, 0, 256, 256);
      saveImage(imageName, pixelData);
    } else {
      createImageBitmap(image, 0, 0, 256, 256)
        .then((ibm) => saveImage(imageName, ibm));
    }
  });

}

In order to extract meaningful pixel data from my saved image, I have another function which also considers priority

function getPixelData(savedImageData, xyPosition, priority) {

  let RGBA;

  if (priority === 'speed') {

    // Tile data in form of ImageData,
    // Simply need to get pixels from position in Uint8ClampedArray 
    RGBA = getRGBfromImgData(savedImageData, xyPosition.x, xyPosition.y);

  } else {
  
    // Tile data in form of ImageBitMap, 
    // need to call .getImageData for coordinate
    var canvas = document.createElement('canvas');
    var c = canvas.getContext('2d');
    c.drawImage(savedImageData, 0, 0);
    var pixelData = c.getImageData( 
      xyPosition.x, xyPosition.y, 1, 1
    ).data;

    RGBA = {
      R: pixelData[0],
      G: pixelData[1],
      B: pixelData[2],
      A: pixelData[3],
    };
  }

  return RGBA;
}

Everything is working exactly as expected when the priority is speed. The image is loaded, then written to a canvas, its image data gotten, and saved as the Uint8ClampedArray. However, when using priority = 'storage', I am getting inconsistent results. Sometimes, it works as expected and I am getting back good RGBA values. But many times, with certain image urls, I am getting all 0s for RGBA values (when for the same image urls, I get good RGBA values for priority = 'speed'.)

I also tried first doing a c.drawImage(image, 0, 0, 256, 256) and then createImageBitmap(c.canvas), just to be sure the image data was there. No change. I also tried playing with ImageBitmapRenderingContext, but I can't drawImage on that, nor can I getImageData from it.

What is going wrong in the conversion of my image to an ImageBitmap and then later back to a Uint8ClampedArray that my values sometimes end up as 0s? Is there a better way to store RGBA image data in memory that still allows fast retrieval of values?

Thanks for reading.

0

There are 0 answers