HTML5 Canvas [60]
context.putImageData (imagedata, dx, dy [, dirtyX, dirtyY,
dirtyWidth, dirtyHeight ])
The first constructor simply paints the entire ImageData instance to the destinationX (dx) and destinationY (dy) locations. The second constructor does the same, but allows the passage of a “dirty rectangle,” which represents the area of the ImageData to paint to the canvas.
Application Tile Stamper
We are going to create a simple application that will allow the user to highlight a box around some pixels on an image, copy them, and then use them as a stamp to paint back to the canvas. It will not be a full-blown editing application by any means—it’s just a demonstration of one use of the ImageData object.
NOTE
This application will need to be run from a local or remote web server, as most browsers will throw an exception if an application attempts to call getImageData() on a file—even in the same folder on a local machine. The current version of Safari (5.02) does not throw this error.
To create this simple application, we will use the tile sheet from earlier in this chapter. The user will click on a spot on the tile sheet, highlighting a 32×32 square tile. That tile can then be painted onto the bottom section of the canvas. To demonstrate pixel manipulation, we will set the color of the pixels to a new alpha value before they are painted to the screen. This will be the humble beginning to making our own tile map editor.
Once again, we will use the tanks_sheet.png file from Figure 4-7.
How ImageData.data is organized
The ImageData.data attribute is a single-dimensional array containing four bytes for every pixel in the ImageData object. We will be using 32×32 tiles in our example application. A 32×32 tile contains 1,024 pixels (or 1K of data). The ImageData.data attribute for an ImageData instance that holds a 32×32 image would be 4,096 bytes (or 4K). This is because a separate byte is used to store each of the red, green, blue, and alpha values for each pixel. In our application, we will loop through each pixel and set its alpha value to 128. Here is the code we will use:
for (j=3; j< imageData.data.length; j+=4){
imageData.data[j] = 128;
}
We start our loop at 3, which is the fourth attribute in the array. The single-dimensional array contains a continuous set of values for each pixel, so index 3 represents the alpha value for the first pixel (because the array is 0 relative). Our loop then skips to every fourth value in the array and sets it to 128. Once the loop is complete, all pixels will have an alpha value of 128.
NOTE
As opposed to other Canvas alpha manipulations where the alpha value is between 0 and 1, the alpha value is between 0 and 255 when manipulating it via the pixel color values.
A visual look at our basic application
Figure 4-13 is a screenshot of the simple Tile Stamper application we will create.
NOTE
Figure 4-13 is running in Safari 5.1 locally. As of this writing, this is the only browser that does not throw an exception when trying to manipulate the pixel data of a locally loaded file when not run on a web server.
Figure 4-13. The Tile Stamper application
The screen is broken up into two sections vertically. The top section is the 256×128 tile sheet; the bottom is a tile map of the same size. The user will select a tile in the top section, and it will be highlighted by a red square. The user can then stamp the selected tile to the tile map drawing area in the lower portion. When a tile is drawn in this lower portion, we will set its alpha value to 128.
Adding mouse events to the canvas
We need to code our application to respond to mouse clicks and to keep track of the current x and y positions of the mouse pointer. We will set up two global application scope variables to store the mouse pointer’s current position:
var mouseX;
var mouseY;
We will also set up two event listener functions and attach them to the theCanvas object:
theCanvas.addEventListener("mousemove", onMouseMove, false);
theCanvas.addEventListener("click", onMouseClick, false);