JavaScript Day 30: More pixels

Yesterday we looked at getting the pixels out of a canvas context via ImageData. Today we’ll look at getting the pixels defined in an ImageData object and drawing them back to a canvas.

Essentially, it’s the same as getPixelData in reverse. You take an ImageData and call context.putImageData(imageData, x, y). Simple enough. The x and y determine where on your canvas the image data rectangle will be drawn. Note that this put function is very low level. It directly draws pixels and ignores any transforms, styles, or shadow definitions, etc.

There are four optional arguments that you can pass in to putImageData, which will define a rectangle within the image data to draw. For example, if you had an ImageData that was 100×100, but you only wanted to draw the lower right hand quarter of it, you could call context.putImageData(imageData, 0, 0, 50, 50, 50, 50). This would define a 50×50 rectangle beginning at an x, y position of 50, 50 and draw it at the 0, 0 location in the canvas.

So a lot of image processing routines could be written with the following pattern:

[php lang=”JavaScript”]imageData = context.getImageData(canvas.width, canvas.height); // get the pixels
// loop through the imageData and perform some algorithm on the pixel data
context.putImageData(imageData, 0, 0); // write the altered pixels back[/php]

But there’s one more thing we can do – create an empty ImageData and set its pixels completely through code. You create a new ImageData object with a factory function on context called createImageData, passing in a width and a height. This gives you an ImageData object with the specified width and height and all the pixels set to zero. Now you can algorithmically fill them with whatever values you want. If you’re looping through them, you’d use pretty much the same technique we used yesterday to loop through and read them.

This next example does just that, using some simple trig to create some waves of color on the red, green and blue pixels.

[php lang=”JavaScript”]$(function () {
var canvas, context, image, imageData, x, y, offset;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);

imageData = context.createImageData(canvas.width, canvas.height);

for(y = 0; y < imageData.height; y += 1) { for(x = 0; x < imageData.width; x += 1) { offset = x * 4 + y * 4 * imageData.width; imageData.data[offset] = Math.sin(x * 0.01) * 127 + 128; imageData.data[offset + 1] = Math.sin(y * 0.02) * 127 + 128; imageData.data[offset + 2] = Math.cos(x * 0.04 + y * 0.03) * 127 + 128; imageData.data[offset + 3] = 255; } } context.putImageData(imageData, 0, 0); });[/php] Other than the trig itself, it's all stuff that's already been explained. This will give you something like the following:

One other thing I should mention is yet another way to create an ImageData object – by passing in an existing one to copy, like so: context.createImageData(oldImageData). This takes an existing ImageData and makes a brand new one with the same width and height, and fills it with all the same pixel values. Useful if you want to manipulate the pixels, but keep the old ones around.

This entry was posted in JavaScript. Bookmark the permalink.

4 Responses to JavaScript Day 30: More pixels

  1. zproxy says:

    Hey, you should post links to your experiments in order to run them.

  2. Evan Mullins says:

    I’m guessing you’ve seen this already: http://desandro.com/resources/close-pixelate/

    Thought I’d share anyways though. Very interesting application of this very thing.

  3. Owaun says:

    Hi I am trying to get this done using processing [www.processing.org] but all I am getting and greyscale bands.

    Here is the code I am using

    PImage imageData;
    void setup(){
    size(255,255,P3D);
    imageData = createImage(255,255,ARGB);
    for(int y = 0; y < imageData.height; y += 1) {
    for(int x = 0; x < imageData.width; x += 1) {
    imageData.set((x*2),(y*1),color(cos(x * 0.04 + y * 0.03) * 127 + 128));
    imageData.set((x*2)+1,(y*1)+1,color(cos(x * 0.04 + y * 0.03) * 127 + 128));
    }
    }
    image(imageData,0,0);
    }

  4. owaun says:

    Koogy at forum.processing.org helped me out with the algorithm in Processing [www.processing.org] Here it is..

    void setup(){

    size(555,555,P3D);
    PImage imageData = createImage(width,height,ARGB);
    loadPixels();
    int offset = 0;
    for(int y = 0; y < imageData.height; y += 1) {
    for(int x = 0; x < imageData.width; x += 1) {
    pixels[offset] = color(
    (int)(Math.sin(x * 0.01) * 127 + 128), // red
    (int)(Math.sin(y * 0.02) * 127 + 128), // green
    (int)(Math.cos(x * 0.04 + y * 0.03) * 127 + 128), // blue
    (int)(Math.sin(x * 0.01) * 127 + 128) // alpha
    );
    offset++;
    }
    }
    updatePixels();
    }

Leave a Reply