How to Manipulate Pixels on JavaScript's Canvas for HTML5 and CSS3 Programming - dummies

How to Manipulate Pixels on JavaScript’s Canvas for HTML5 and CSS3 Programming

By Andy Harris

The <canvas> tag in JavaScript has one more incredible trick up its sleeve for HTML5 and CSS3 programmers. You can extract the data of a <canvas> tag into the underlying pixel data. If you know how to manipulate this data, you can have extensive control of your image in real time. You can use this data for color balancing, as well as experimenting with custom blurs, sharpens, and chroma-key effects.

In order to understand how to have this much control of your images, you need to have some knowledge of how pictures are stored in memory. No matter what format an image is stored in on the file system, it is displayed as a list of pixels. Each pixel is represented (in the standard 32-bit system, anyway) by four integers: RGBA.

The R value represents how much red is in the current dot. G stands for green, and B stands for blue. The A stands for alpha, which is a measure of the transparency of the image. Each of these values can vary from 0 to 255.

When you convert an image to the imageData, you get a huge array of integers. Each group of four integers represents a single pixel of color data.

Here’s an example that changes the color balance of an image:

 function draw(){
 //from pixel.html
 var drawing = document.getElementById("drawing");
 var con = drawing.getContext("2d");
 var original = document.getElementById("original");
 CANV_WIDTH = 200;
 CANV_HEIGHT = 200;
 //draw the original on the canvas
 con.drawImage(original, 0, 0);
 //get the image data
 imgData = con.getImageData(0, 0, 200, 200);
 //loop through image data
 for (row = 0; row < CANV_HEIGHT; row++){
  for (col = 0; col < CANV_WIDTH; col++){
  //find current pixel
  index = (col + (row * imgData.width)) * 4;
  //separate into color values
  r = imgData.data[index];
  g = imgData.data[index + 1];
  b = imgData.data[index + 2];
  a = imgData.data[index + 3];
  //manipulate color values
  r -= 20;
  g += 50;
  b -= 30;
  a = a;
  //manage boundary conditions
  if (r > 255){
   r = 255;
  }
  if (r < 0){
   r = 0;
  }
  if (g > 255){
   g = 255;
  }
  if (g < 0){
   g = 0;
  }
  if (b > 255){
   r = 255;
  }
  if (b < 0){
   b = 0;
  }
  if (a > 255){
   a = 255;
  }
  if (a < 0){
   a = 0;
  }
  //return new values to data
  imgData.data[index] = r;
  imgData.data[index+1] = g;
  imgData.data[index+2] = b;
  imgData.data[index+3] = a;
  } // end col for loop
 } // end row for loop
 //draw new image onto canvas
 con.putImageData(imgData, 0, 0);
 } // end functionAlthough the code listing seems quite long, it really isn't too difficult to follow:
  1. Draw an original image.

    The technique you’ll use extracts data from a <canvas> element, so to modify an image, first you need to draw it onto a canvas.

  2. Extract the image data.

    The getImageData() method gets the picture displayed by the current canvas and places it in a huge array of integers.

  3. Make a loop to handle the rows.

    Image data is broken into rows and columns. Each row goes from 0 to the height of the canvas, so make a for loop to iterate through the rows.

  4. Make another loop to handle the columns.

    Inside each row is data from 0 to the width of the canvas, so make a second for loop inside the first. It’s very common to use a pair of nested for loops to step through two-dimensional data like image information.

  5. Find the index in imageData for the current row and column.

    The imageData array contains four integers for each pixel, so you have to do a little math to figure out where the first integer for each pixel is. The easiest formula is to multiply the row number by the width of the canvas, add that to the column number, and multiply the entire result by four.

  6. Pull the corresponding color values from the index.

    The index also represents the red value of the current pixel. The next int holds the green value, followed by the blue value, and finally the alpha value.

  7. Manipulate the color values as you wish.

    If you’re going to do a color-balancing app, you can simply add or subtract values to change the overall color balance.

  8. Check for boundaries.

    A pixel value cannot be lower than 0 or higher than 255, so check for both of these boundaries and adjust all pixel values to be within legal limits.

  9. Return manipulated values back to the imgData array.

    You can copy values back to the array, and you should do so, to make the changes visible.

  10. Draw the back to the canvas.

    The putImageData() function draws the current image data back to the canvas as an ordinary image. The new version of the image will reflect the changes.