Intro to Processing II - All About Images

From Interactivity

Contents

Review

Now that you know something about the basics of Processing, we can move on to higher-level objects like images.

  • setup()
  • draw()
  • basic datatypes (int, float)
  • mouse methods and variables
  • keyboard methods and variables
  • Strings (and adding /concatenating)
  • debugging methods like println()
  • loops
  • logical expressions - if/else
  • Objects & classes (you'll pick this up as we go on)

Here's a review sketch from the workshop that shows you how to draw some basic shapes and calculate the time it takes for Processing to draw each frame (which you could later use for frame-independent animation).

Overview

The PImage class is responsible for handling images in Processing. But what are "images," exactly? Just like what you see on the screen, an image is, at a basic level, a collection of pixels. In Processing, images are contained in a single-dimensional array of size image.width*image.height, in order of rows from the top of the image down to the bottom, very similar to pixels on the screen.

The PImage class has a number of methods for dealing with images, such as masking, copying, drawing, and filtering, as well as a handy array called pixels[] that contains all of the pixels in the image (more o this soon).


Topics

We will refer to this sketch called imageLumaAlpha, which combines virtually all topics together into one tasty little package.


Image formats

Type:

println(javax.imageio.ImageIO.getReaderFormatNames());

into a Processing sketch and hit play. You'll see a list of supported images in the bottom black output section of the window. These are types of images you can read in Processing.

To get a list of formats of images you can write, type:

println(javax.imageio.ImageIO.getWriterFormatNames());


Loading images

Drawing images to the screen

Basic drawing to the screen uses the method [file:///Applications/Processing.app/Contents/Resources/Java/reference/image_.html img()], which takes a screen position (remember, (0,0) is the top left corner of the screen and (width,height) is the bottom right) and an optional width and height:

//draw an image to the top left corner of the screen
image(img, 0,0);


//draw an image to the top left corner of the screen
//and scale it to 80px wide by 60px tall
image(img, 0,0, 80,60);


Images are drawn from their top left corner. You might expect them to be drawn outwards from their center - this is easily changed by the method imageMode(CENTER); or back again by imageMode(CORNERS);


You can also draw parts of an image to the screen using copy():

 copy(srcImg, x, y, width, height, dx, dy, dwidth, dheight)

This will take a region of an image and draw a scaled version into the main window.


To tint and image, or make it partially transparent, use the tint(R,G,B,A); method:

//set the tint to half-transparent for all successive images
//drawn to the screen
tint(255,255,255,127);
image(img, 0,0);


Copying images

(whole, parts)

You can copy an image to another PImage, in whole or in parts.

 // get a section of the image starting at position x,y
 // that is width,height in size
 PImage myOtherImage = myOriginalImage.get(x,y, width,height);

Or use get() with no arguments to get the entire image.


NOTE: You'll notice that this will actually make a copy of the PImage object. This is much different than just decalring a new PImage object and setting it equal to another:

PImage myOldImage = loadImage("someImage.jpg");
PImage myNewImage = myOldImage;

This is because myOldImage represents an object, not a data primitive like an int, float, or char. Think of it this way - referring to a data primitive by name is like holding a small stone in your hand. You pass this stone around your program as if it physically existed. An object is like a bucket of stones that you don't have a direct hold on, as if the name you call it is a piece of string attached to a bucket that holds the stones. What you refer to when you write the name of the object is to that "string" attached to the bucket - not the bucket itself. So setting myOldImage equal to myOriginalImage sets it to the "string" that is tied to a single object, and not two copies of the object.


Manipulating pixels

Pixels (red,green,blue,alpha values) are stored in an array internal to each PImage object called pixels[]. Before using it, you must load all the pixels into memory by calling the method loadPixels(), and if you change any pixel values, when finished you call updatePixels(). Why? Because pixel data is stored in a variety of formats internally, and converting them into an easy-to-access array of values like pixels[] takes time.

Drawing into images and PGraphics


http://themushroomkingdom.net/media/mkdd/images