Convert an image to an RGB array in Javascript - javascript

Is it possible to get an array of pixels from a PNG or BMP image in Javascript? I'd like to obtain an RGB array from an image so that I can manipulate the array of pixels, and then draw the modified image on a canvas.
UPDATE: I found an exact duplicate here: how to get the RGB value of an image in a page using javascript?
However, the answers don't go into much detail about how to actually solve this problem.

There are a hundred tutorials on the net about using HTML Canvas imageData, which gets the RGBA values of an canvas. Do a search for canvas imageData and you'll find plenty of info.
All you have to do is:
ctx.drawImage(img, 0, 0);
var imgData = ctx.getImageData(x, y, width, height).data;
imgData is now an array where every 4 places are each pixel. So [0][1][2][3] are the [r][g][b][a] of the first pixel.

Related

Canvas imagedata multiple pixel insert

I am retrieving pixels in a canvas imagedata and I'm doing that a lot.
I think the inserting and retrieving from and to the canvas imagedata is expensive in cpu time, so I want to make as few of those as possible.
One way of cutting that would be to make a single insert that would insert multiple pixels in a single sequence, but so far I have not been able to see how that would be done. All the examples I have seen so far retrieve and insert only a single pixel.
So the question is,
in order to speed up canvas imagedata pixel manipulation, how do I insert/retrieve multiple pixels simultaneously?
Just select a larger region when retrieving a pixel buffer:
var imageData = ctx.getImageData(x, y, width, height);
^^^^^^^^^^^^ not limited to one
Now your data buffer will contain all pixels for the given region. To get the whole canvas:
var imageData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
Adjust them and put back into the same position:
ctx.putImageData(imageData, x, y);
and you're done.
Remember that each pixel consists of four bytes (RGBA). To address a larger buffer you can do:
function getPixelIndex(x, y) {
return (y * width + x) * 4; // width used when getting buffer
}
Tips:
if you plan to update the same buffer often simply retrieve the buffer once and store a pointer to it, update it when you need and put back, then reuse the same buffer. This way you save the time getting the buffer. This won´t work if you in the mean time apply graphics to the canvas with standard methods.
You can also start with an empty buffer using createImageData() instead of getImageData().
If your pixel color data is more or less static you can update the buffer using a Uint32Array instead of the Uint8ClampedArray. You get a 32-bit version like this after getting the imageData:
var buffer32 = new Uint32Array(imageData.data.buffer);
Your new buffer32 will point to the same underlying byte buffer so no significant memory overhead, but it allows you to read and write 32-bit values instead of just 8-bit. Just be aware of that the byte order is (typically) little-endian so order the bytes as ABGR. Then do as before, call ctx.putImageData(imageData, x, y); when you need to update.

HTML Canvas imageData array all 0's

var img, imageData,width,height;
var c = canvasEle.getContext("2d");
width = canvasEle.width;
height = canvasEle.height;
img = document.getElementById("id");
c.drawImage(img,0,0);
imageData = c.createImageData(width, height);
After I draw the image onto the context, then create an imageData array, the values of the array are all 0.
I have been struggling with this for hours and couldn't find any solution. The image is shown on the canvas after I draw it, but the imageData of the context says all the pixels are white. This doesn't make any sense to me.
With createImageData you are creating new image data for an empty image. Please use getImageData to get the image data from an already existing canvas

HTML5 Canvas to PNG zeroes all channels when alpha transparent

I have a Uint32Array I am trying to convert to a texture for WebGL. To do this I'm writing the array as RGBA values on a Canvas and getting a base64 encoded PNG from the canvas to send as a texture.
Whenever I set a pixel value to have an alpha of 0, the corresponding RGB channels are also zeroed upon conversion to a PNG. Is this an implementation detail? If I were to create PNGs in some other non-HTML5 program could I have an (RGBA) quadruplet of (255,255,255,0)? I tried using an alpha value of 1 and all other channels remain intact, so this is not an issue of premultiplied alpha.
Here is some javascript code to reproduce this effect:
var img = new Image();
var canvasObj = $('<canvas width="1" height="1"></canvas>');
var context = canvasObj[0].getContext('2d');
var imgd = context.getImageData(0,0,1,1);
var pix = imgd.data;
pix[0]=255; pix[1]=255; pix[2]=255; pix[3]=0;
context.putImageData(imgd,0,0);
img.src = canvasObj[0].toDataURL("image/png");
context.drawImage(img,0,0);
var imgd2 = context.getImageData(0,0,1,1);
var pix2 = imgd2.data;
pix2 will be all 0s.
Thanks!
It appears to be part of the PNG specification (http://www.libpng.org/pub/png/spec/1.2/png-1.2-pdg.html).
...fully transparent pixels should all be assigned the same
color value for best compression.
I couldn't find a direct source, but it seems like this particular implementation sets all the channels to zero.

Can JavaScript canvas be manipulated like a bitmap, and is it optimized for that use?

Can a JavaScript canvas be manipuled like a standard bitmap (accessing/modifying a pixel and getting it's size)? Is this use optimized, or would it be faster to manipulate normal 2d arrays of pixels and draw over canvas when you need it?
Absolutely yes! Please have a look here:
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Pixel_manipulation_with_canvas
As for your second question, as per the pixels documentation, pixels is a one dimensional array. You'll need to do your own 2 x 2 hoopla for a 2d way.
Taken from a previous SO answer by I82Much (works dandy for me):
int row = i;
int col = j;
int offset = row * width + col;
color p = pixels[offset];
More here: how to loop over the pixels using 2D array?
and here: http://www.processing.org/reference/pixels.html
You can get an array of pixel data from the canvas context using getImageData(). Bear in mind that each pixel takes-up 4 spaces in the array (for red, green, blue and alpha). Then, once you've altered the array to your liking, you can use putImageData() to put the data back.

Read image pixels

Is it possible to read pixels of an image in canvas A and create pixels on canvas B? And I want to create the new pixels on Canvas B only where the image's pixels are green.
eg. If images' pixel (120,45) is green I need to create a green colored pixel in Canvas B at (120,45)
You can use canvas ImageData to get color values for each pixels. The function:
context.getImageData(left, top, width, height);
returns an ImageData object, which consists of the following properties:
width
height
data (CanvasPixelArray)
The CanvasPixelArray contains the RGBA values for all the pixels, starting from top-left working its way to bottom-right. So in other words, it is an array containing 4*width*height number of entries.
Using that, you can start looping through each pixel (+=4 entries per pixel), and check the RGBA values. If they match a specific value you want, i.e. green, then you would copy that value to a canvas B, which you would create by modifying a newly created ImageData object.
You can create a new empty ImageData object with:
context.createImageData(cssWidth, cssHeight)
Note that you will need to know specific RGBA values that identify "green" or define specific conditions, i.e. if the G value of RGBA is >= 150 then it is "green".
Also note that you cannot get the ImageData that has been tainted resources outside of your origin. i.e., if you draw an image onto the canvas that isn't CORS safe, you won't be able to retrieve the ImageData from that canvas anymore, much like how you can't use toDataURL either.

Categories

Resources