Using Images in Processing

Digital images are typically stored as a rectangular array of pixels that have both a color and, sometimes, a transparency level.

Processing has pretty good support for reading and displaying image files. It works with most major image file formats, including JPEG, PNG, and GIF:

  • The JPEG format is typically used for storing photographs. JPEG does a good job of compressing photographic images at the expense of some image quality. Typically, JPEG images are about 10 times smaller than “raw” images in non-JPEG formats, and the image degradation is often hard to notice. If you look carefully, you might sometimes see small “smudges” in JPEG images that are caused by the compression.
  • The PNG format is typically used for non-photographic images, such as website logos or icons, where it is important that every pixel be precisely rendered. PNG images also let you specify pixels as having different levels of transparency, which is useful for some special effects. PNG files are typically much larger than the equivalent JPEG file, and so it would rarely be a good idea to store a picture from a camera as a PNG.
  • The GIF format is an older file format that was designed for the same sort of images as PNG. For most applications, though, PNG images are superior because PNG files are usually smaller and support more colors and more levels of transparency.

Generally speaking, you should store photographs as JPEG, and non-photographs as PNG.

Displaying an Image in Processing

Here’s a program that displays an image; note that this assumes there’s an image named kandinsky.jpg (which is 1098 pixels wide, and 757 pixels high) in your program’s data folder:

PImage img;   // img is a global variable

void setup() {
  // load the image file from the "data" folder
  img = loadImage("kandinsky.jpg");

  // set the window to be the same dimensions as the image
  size(1098, 757);
}

void draw() {
  // display the image so that its upper-left corner
  // is on the upper-left corner of the screen
  image(img, 0, 0);
}

Lets look at each part of this program:

  • The first line is this:

    PImage img;
    

    This is a global variable declaration statement. It declares the variable img to be of type PImage. PImage is a pre-defined variable type that Processing uses for storing images.

    Every variable in Processing has a type, i.e. a tag that describes the kinds of values that the variable can hold. So here, img is only allowed to contain images, and you’ll get an error if you try to assign it some other type of value (such as a number, or a string).

  • The first line inside setup() loads an image:

    img = loadImage("kandinsky.jpg");
    

    loadImage is a pre-defined Processing function that reads an image file from your program’s data folder.

    If the file can’t be found, then you will get a run-time error from Processing telling you that the file is either missing or inaccessible.

  • The second line of setup() sets the size of the display window to be the same as the image:

    size(1098, 757);
    
  • Inside draw(), there is one statement:

    image(img, 0, 0);
    

    This draws the image on the screen such that the upper-left corner of the image is at the upper-left corner of the screen.

Note

In version 2 of Processing, it was possible to make the size of the

window match the dimensions of an image with code like this in setup():

PImage img;

void setup() {
  img = loadImage("kandinsky.jpg");
  size(img.width, img.height);
}

However, in Processing 3, this is no longer allowed — you can only pass literal numbers to the size function.

If you do need to pass a variable to size, you must use the special settings() function, which is guaranteed to be called before setup(), e.g.:

PImage img;

void settings() {
  img = loadImage("kandinsky.jpg");
  size(img.width, img.height);
}

Things to Try

After you get this basic program running, see what happens when you make the following changes:

  • Replace image(img, 0, 0) with image(img, 50, 50).

  • Replace image(img, 0, 0) with image(img, mouseX, mouseY), and try moving the mouse around while the program is running.

  • Drawing a background before drawing the images removes the “trail”. For example, replace image(img, 0, 0) with these statements:

    background(255);   // make the background white
    image(img, mouseX, mouseY);
    
  • Replace image(img, 0, 0) with these statements:

    background(255);   // make the background white
    image(img, mouseY, mouseX);
    
  • You can display an image more than once. For example, replace image(img, 0, 0) with these statements:

    background(255);   // make the background white
    image(img, mouseX, mouseY);
    image(img, mouseY, mouseX);
    
  • The background function lets you display an image as the background. For example, image(img, 0, 0) with this:

    background(img);  // draw img as the background
    
  • You can use the same image in different ways, e.g.:

    background(img);  // draw img as the background
    image(img, mouseX, mouseY);
    image(img, mouseY, mouseX);
    

Questions

  1. What is a global variable?

  2. Why is it usually a very bad idea to call loadImage on an images on a website?

  3. What happens if you call loadImage on a file that doesn’t exist? What if you call it on a file that is not an image?

  4. Describe in English what this statement does:

    image(ball, mouseX, mouseY);
    

Programming Questions

  1. Using an image of your choice, write a program that draws three copies of that image on the screen, and all three images move in the same direction the mouse pointer moves.
  2. Re-do the previous question except this time make the three images each move in different directions when you move the mouse pointer.
  3. Create a program that displays two images, a background image that doesn’t move and some other image that follows the mouse pointer around. You will need two different PImage variables for this, one called bg (for the background) and the other called img.