I'm writing an electron app where a user will select an image from disk. I need to read the contents and display them in a canvas for editing purposes, and to do this I need to do two things:
1.) Read the contents of the image and put them in a Canvas
2.) Determine the dimensions of the image.
To achieve the first, I'm reading the file contents with fs.readFileSync:
let imageData = fs.readFileSync(pathToFile);
This gets me a Uint8Array when loading up a PNG. To place it into my canvas I'm attempting to create an ImageData which requires a Uint8ClampedArray, so I'm attempting a conversion like this:
let array = new Uint8ClampedArray(this.imageBuffer);
let imageData = new ImageData(array, canvas.width, canvas.height); // Error
ctx.putImageData(imageData, 0, 0);
However, while the file seems to load fine, there's obviously more work I need to do to get it onto a canvas because this gives an error stating:
"Failed to construct 'ImageData': The input data length is not a multiple of 4."
I'm assuming the data I'm reading straight from my PNG isn't in the correct format to write into an ImageData, so what can I do to format it correctly? And how would I be able to determine the dimensions of the original image with this data?
Your Uint8Array
holds the binary data of your image file in whatever format it is, it's not the raw image data that ImageData
requires.
Luckily for you createImageBitmap()
can accept binary data directly and decode it correctly to an ImageBitmap
, exposing the image's dimension and that can be drawn to a canvas directly.
For this you'd need to pass a Blob
though.
It seems that Electron's fs
still doesn't provide a method to get a Blob from a path so we'll have to make one from the Uint8Array
, which means we'll have to have the data twice in memory... (for a short time).
const data = fs.readFileSync(pathToFile);
const bmp = await createImageBitmap(new Blob([data]));
const {width, height} = bmp;