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.