Question

I am using an html5 canvas to render and image, do some basic editing of the image than trying to use the getImageData(0 function to read through the pixels and do some work. I have notices thou, no matter what bit depth the source image is (8 bit, 16 bit , 24 bit) the getImageData() method allows returns 8-bit (256 colors). this in not desirable. I would like the getImageData(0 method to spit out as many colors as it recieved.

I have read through the documentation and the canvas should be able to handle any bit depth you throw at it (figuratively) but I cant see anywhere to set the bit depth higher

Was it helpful?

Solution

Canvas will always return 24-bit data + an 8-bit alpha channel (RGBA). Each component value will of course have 8 bits or 256 values. This is per specification. It will never return 8-bit indexed image data however so if you somehow run into 8-bit (indexed) image data then you are probably reading the data wrong or from the from object/array.

From the specification:

imagedata . data

Returns the one-dimensional array containing the data in RGBA order,
as integers in the range 0 to 255.

And just to cover the opposite aspect: if you draw in a 8-bit indexed palette image such as a PNG-8 or a GIF using 2 - 256 colors their indexed palette will always be converted to RGBA buffer (it's actually converted to RGBA at load time by the browser so this is not something canvas do itself).

To read data from canvas you have two levels (or three for more advanced use), the image data object which contains various information including a reference to the actual pixel array view:

var imageData = context.getImageData(x, y, w, h);

From this object we obtain the data view for the pixels which is by default a Uint8ClampedArray view:

var pixelData = imageData.data;

And for more advanced usage we could get the raw byte buffer from this (if you need to provide other views, ie. Uint32Array) can be obtained from:

var rawBytes = pixelData.buffer;
var buffer32 = new Uint32Array(rawBytes);

But lets stick to the default 8-bit clamped view - to read from it you need to know that the pixels are always packed into RGBA or as 32-bit values. So we can get a single pixel by doing:

var r = pixelData[0];
var g = pixelData[1];
var b = pixelData[2];
var a = pixelData[3];

The next pixel will start at index 4 and so on.

If you for some reason need to reduce the palette to indexed palette you would have to provide the algorithm for this yourselves. There are many out there from simple and bad to more complex and accurate ones. But this is not something you will be able to do out of the box with canvas. Some pointers can be found in this answer or you can use a library such as this which will create a (animated) GIF from canvas.

Also be aware of that if an image drawn into canvas didn't fulfill cross-origin requirements (CORS) the canvas will be "tainted" (security-wise) and the getImageData() will return a an array with values set to 0.

OTHER TIPS

ImageData (returned by getImageData) property data gives you an array in which each entry is a colour channel in sequence red, green, blue and alpha and not the actual colour. e.g.

red=imgData.data[0];
green=imgData.data[1];
blue=imgData.data[2];
alpha=imgData.data[3];
colour = '#' + (red<16)?'0':'' + red.toString(16) +
(green<16)?'0':'' + green.toString(16) +
(blue<16)?'0':'' + blue.toString(16);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top