Processing is an open source tool designed by Casey Reas and Ben Fry from MIT. It is a java application that was originally created to enable nonprogrammers to make digital artworks.
Processing includes
an integrated development environment (IDE)
a programming language
tools to publish the applications for the web or desktop.
Because Processing runs using Java, it can do almost anything Java can do. You can use it to read and write data, work with images, video or sound, draw in two or three dimensions, create artificial intelligence, and simulate physics.
A Processing sketch has two fundamental methods:
setup()
draw()
The first method is invoked when your application starts and the second is invoked over and over again. It is the main loop of your application.
setup()
Any instructions put in the setup() method run when the application first starts. It is where you prepare the application, like setting up the size and the frame rate.
void setup(){
size(400,400);
//number of times per second that the
//draw() method is called
frameRate(30);
print("all done setting up");
}
Putting something on the screen is easy in Processing:
Using commands like line means everything
you do can give you immediate visual response.
line() does what it sounds like it does, and takes four simple arguments—two pairs of
x and y coordinates. One for the start point and another for the end point.
line(0,0,200,200);
Processing is interactive:
Add a draw() loop, and the line you draw can become interactive if you use the coordinates of the mouse:
void setup() {
size(400,400);
}
void draw() {
background(255); //try moving this line to setup and watch what happens!
line(0,0,mouseX,mouseY);
}
Processing can help you visualize numbers:
The numbers can also be meaningful values – in this case, from the internal clock.
Using variables in place of fixed number values allows you to adjust that value – over time for animation, to transform the value aesthetically,
and to experiment with how code works.
In fact, the best way to start to figure out code – even before you're sure how it works – is often to start
messing around with values. Sometimes breaking code you don't understand can be a great
learning experience. Watch what happens when you move mouseX and mouseY with our interactive line:
//Continuous radial gradient
size(200,200);
background(0);
for (int i=255; i>0; i--){
noStroke();
fill(255-i);
ellipse(width/2, height/2, i, i);
}
And another:
for (int i = 0; i < classes; i++) {
doHomework();
}
Processing can loop over arrays: Using arrays (lists) with loops can help to simplify code,
even in a simple example – loops and lists are a natural match for one another, since the former lets you iterate through the latter.
Processing can have loops within loops: You can also place a loop inside a loop. Huh?
It helps to see the result.
int[] circles = {170,113,78,30,13};
size(400,400);
background(150);
noStroke();
smooth();
for (int j=0;j<4;j++) {
for (int i=0;i<circles.length;i++){
fill(random(0,255),random(0,255),random(0,255));
ellipse((width/4)*j,(height/4)*j,circles[i],circles[i]);
}
}
You can extend the loops within loops concept to more involved iteration, such as iterating through columns, then rows – essential to
processing the individual pixels in an image.
Curly braces{}
The curly brace is a syntactical structural element. They always appear
in balanced pairs (an open and closed brace), and are used to
structure blocks of code.
Here's a conditional if...else example:
you might consider the cake's attributes and what can be done to
it (make a cake, eat a cake, throw a cake on the ground), and then organize your cake class
relative to smaller categories of related things (cupcakes) and bigger categories of things (dessert).
Procedural programming uses functions to organize a
program.
In OOP, you build much more complex structures called
classes.
To use a class, you create
instances of it, known as objects.
Cat myCat=new Cat();
Classes contain properties and methods. You can think of
the properties as the traits of the object and the
methods as actions you perform on/with
the traits. For example, if you create a class called Cat,
some of the properties might be
color, weight, and markings, and a method might be getBreed().
You use the dot syntax
as a way to connect an object with its properties and/or methods.
If you
create an object Clark from the Cat class,
the object can call the getBreed() method
using dot syntax, like this:
Processing uses a language specifically designed to generate and modify images.
This program
allows you to write Java programs with
much simpler code. It also
allows you to structure your code in a function-based (procedural), non–object-oriented
style. But once you compile your code, the output is converted to Java class files—
indistinguishable from any other Java program—and the class files are interpreted within
the Java Virtual Machine as your program runs.
Processing programs are created from instructions known as commands;
a group of commands together is called source code.
When you tell it to, your computer will look at this source code and carry out the
commands within, drawing lines, playing sounds and doing whatever else you've
told it to do. A process not unlike giving someone written
instructions and making him or her follow them to the letter.
In the Processing environment, you edit your source code (your list of commands)
in the main window and give it to the computer to run by pressing
the play.
The Application Interface
Processing is an integrated development environment
(IDE).
While the Flash IDE has a steep learning curve, Processing's is simple to work with.
Processing has three modes of working, allowing
coders, as they increase their programming literacy, to move from Processing's simplified
procedural approach, to a hybrid approach that uses some more-advanced programming
constructs, to ultimately working in pure Java—all in the same IDE.
Below are the descriptions of the six control buttons:
The
run button is the same as in Director and Flash. Press this
to see your code execute as a program. Alternatively you can type ⌘+R.
Pressing ⌘+SHIFT+R creates a full-screen
display of your executing sketch. The sketch window is centered against a neutral
background. You can stop the display by selecting the Stop command in the lowerleft
corner of the screen, or by pressing the Esc key.
The
stop button is the same as in Director and Flash. Press this
to see your program stop executing.
Creates
a new file. Processing calls them sketches. You can
even call them applets, programs, or interactive pieces. Director
and Flash call them movies.Alternatively type ⌘+N.
Open
a pre-existing sketch. A menu will pop up and you can choose from
your own collection, saved in the special Processing sketch folder
which I will show you later. You can also choose from a wide variety
of example sketches by famous new media designer/artists, in order
to learn from them and use them as a code reference.
Alternatively type ⌘+O.
Save
the current sketch into the Processing sketches folder.
Alternatively type ⌘+S.
If you want
to give the sketch a name other than the current date, you can choose
save As from the File menu. Alternatively type ⌘+SHIFT+S.
Export
the current sketch into the Processing sketches folder - this time
as a Java applet - complete with its very own HTML file. Alternatively type ⌘+E.
To Export Application press ⌘+SHIFT+E. This allows
you to export your sketch as a stand-alone, platform-specific executable application.
Export Application generates an entire directory
structure (in this case, actually three separate directories) with all the required files
to launch an application under Linux, OS X, and Windows.
Other useful commands
Sketch menu
Show Sketch Folder ( ⌘+K): Opens up the directory
of your current sketch. If you haven't moved it, your current sketch directory will reside within
your main sketchbook directory.
Sketch>Add File: Opens a file navigator, allowing you to load an image, font, or other media
into a data subdirectory within your sketch directory. If no data directory exists,
Processing will automatically create one for you.
Tools Menu
Auto Format (⌘+T): This command attempts to
format the code layout for optimal readability. Skipped lines, also referred to as
whitespace, are retained. Syntax errors, such as missing semicolons, are not corrected.
Create Font: The command
opens the Create Font dialog box, which allows you to select any font
installed on your system. This dialog includes the options Size,
Filename, Smooth (for anti-aliasing), and All Characters. The font generated is a copy
of an existing font in your system, created in the VLW font format and installed
within a data subdirectory in the current sketch directory. Similar to loading other
media into Processing, a data directory is automatically created, if one doesn't
already exist. There are some memory concerns involved in creating fonts this way.
The larger the font size you specify, the more memory the font will use, as each
font includes the actual raster information needed to draw the individual characters;
normally, fonts are created using vector data. In addition, the Smooth option
also requires a little more memory, as does the All Character option, which includes non-English characters, such as ü and Å.
Color Picker: This is a simple color picker, showing you the HSB (hue, saturation,
brightness), RGB, and hexadecimal color values of the color selected.
Archive Sketch:
This command creates a ZIP archive of the current sketch, prompting
you with a Save dialog to choose a location to save the archive.
Syntax Structure
Statements —>elements that make up programs.
; or statement terminator—>used to end statements.
If you leave it off the end of your statement, the program will not run.
//Comments —>used for making notes to help people better understand programs.
// A comment begins with two forward slashes
The size() function is a statement that tells the computer
how large to make the window.
Function statements take zero or more parameters.
Parameters are data passed into the method and used as values for specifying what the computer will do. size(200, 200);
The background() function is a statement that tells the computer
which color to make the background of the window background(102);
Processing uses
println()
to print data, followed by a carriage return, to the output window.
Program/Language
Code
Processing
println()
Java
System.out.println()
Flash/ActionScript
trace()
Director/Lingo
put
Processsing uses typed variables.
If you are using a variable that is a number you must declare what type of number your variable
is:
byte,short,int,long,float, or double
int
x = 0;
println(x);
x=x+1;
println(x);
x=x+1;
println(x);
Press
play and see this:
0
1
2
3
Because you set the data type of variables when they are declared in Processing and Java,
and that information gets put in the compiled bytecode, the virtual machine (the language
interpreter) needs to do less work. Languages like Processing and Java that work this way
are called statically typed languages.
Languages like Python are
dynamically typed, and, due in part to dynamic typing,
run slower than Java and
Processing.
Conditionals or if-then statements:
Processing comes with several code examples. To open them select: File>Sketchbook>Examples>...
Programming Modes
Basic Mode
In basic mode, you simply type individual lines of commands sequentially into the text
editor window, without the added complexity of more complex structures, such as functions
or classes. The following code is
structured in basic mode and generates a simple red circle, with a black stroke on a yellow
background:
size(200, 200);
background(255, 255, 0);
stroke(0);
fill(255, 0, 0);
int x = 100;
int y = 100;
int w = 140;
int h = 140;
ellipse(x, y, w, h);
Continuous mode
In continuous mode, you build upon basic mode, with the edition
of code structures called functions and classes.
Functions are the main building
blocks used in procedural programming, and are simply groupings of lines of code that
execute only when they are explicitly called. Classes are more complicated structures
than functions, and are utilized in OOP.
In
basic mode, code is executed linearly (line by line). Functions and classes, on the other
hand, allow code to be executed nonlinearly.
In continuous mode, two basic Processing functions are provided:
void setup(){
}
void draw(){
}
The setup() function is called only once, at the start of the program. This is the place
where you normally initialize variables that will be used later in the program. Adding the
setup() function to your sketch allows you to add your own additional custom functions
and classes.
The draw() function adds animation capabilities to your sketch and has a
built-in loop, more accurately called a thread or timer. By default, adding the draw() function
to your sketch causes any code between the curly braces of this structure to continuously
execute. Java mode
This mode allows you to work in pure Java, from directly within the Processing text editor.
Java mode is extremely flexible, giving you access to the entire Java API.
//Rendering modes
Processing has three rendering modes: JAVA2D, P3D, and OPENGL. The
mode can be explicitly set as an optional argument within Processing's size() method. For
example, to use the P3D rendering mode, you would write: size(200, 200, P3D). The
rendering modes control how visual data is rendered, or converted to pixels on the screen.
This applet uses P3D: OPENGL mode P3D mode utilizes a software-based 3D engine, meaning that all the 3D calculations are
handled by Java, just as normal 2D calculations are; the 3D math is crunched and converted
to 2D data before being sent to the graphics hardware to draw the image to the
screen. However, your
graphics hardware has the capability to crunch numbers, and in fact can do it much faster
than Java. The trick, though, is in communicating directly with the graphics hardware to
speed things up.
OpenGL is a platform-independent library that functions as an interface between your
code and the graphics hardware. OpenGL was developed in 1992 by Silicon Graphics, but
is now overseen by a large group of organizations, under the heading OpenGL
Architecture Review Board.
To use the OpenGL library in Processing add the
OPENGL string as a third argument to the size function call: size (800, 600, OPENGL);:
When drawing ellipses and rects you can also specify where to start drawing by calling the ellipseMode() or rectMode() functions before drawing your shapes:
Using variables in place of fixed number values allows you to adjust those values – over time for animation, to transform the value aesthetically,
and to experiment with how code works.
In fact, the best way to start to figure out code – even before you're sure how it works – is often to start
modifying values. Sometimes breaking code you don't understand can be a great
learning experience. Watch what happens when you move mouseX and mouseY with the interactive line:
//Continuous radial gradient
size(200,200);
background(0);
for (int i=255; i>0; i--){
noStroke();
fill(255-i);
ellipse(width/2, height/2, i, i);
}
And another:
for (int i = 0; i < classes; i++) {
doHomework();
}
Processing can iterate over arrays:
Using arrays (lists) with loops can help to simplify code,
even in a simple example – loops and lists are a natural match for one another, since the former lets you iterate through the latter.
You can extend the loops within loops concept to more involved iteration, such as iterating through columns, then rows – essential to
processing the individual pixels in an image.
Exercise
Recreate the following sketch:
from Lorenzo Bravi's Procedure di Basic Design
Transformations exist in 2D and 3D space
translate() specifies an amount to displace objects within the display window. The x parameter specifies left/right translation, the y parameter specifies up/down translation, and in 3D the z parameter specifies translations toward/away from the screen. Using this function with the z parameter requires using the P3D or OPENGL parameter in combination with size().
Transformations apply to everything that happens after and subsequent calls to the function accumulates the effect. For example, calling translate(50, 0) and then translate(20, 0) is the same as translate(70, 0). If translate() is called within draw(), the transformation is reset when the loop begins again. This function can be further controlled by the pushMatrix() and popMatrix().
Design a minimal geometric face. Next, write code in Processing to draw your face in a 500 x 500 pixel window. Then, extend your code by adding one variable called "v" that controls the face so the expression continuously changes as the mouse moves from left to right across the display window.
from Casey Reas's Interactivity UCLA Design Media Arts 2012 class and Lorenzo Bravi's Procedure di Basic Design
Here's another way to do it. Save the frame as a PDF.
import processing.pdf.*;
void setup() {
size(400, 400);
beginRecord(PDF, "everything.pdf");
}
void draw() {
// Be sure not to call background, otherwise your file
// will just accumulate lots of mess, only to become invisible
// Draw something good here
line(mouseX, mouseY, width/2, height/2);
}
void keyPressed() {
if (key == 'q') {
endRecord();
}
if (key == 's') {
beginRecord(PDF, "everything####.pdf");
}
}
Saving multiple frames
boolean recording = false;
void setup() {
size(640, 360);
smooth();
background(0);
}
void draw() {
//your interaction here
if (recording) {
println("recording");
saveFrame("output/frames####.png");
}
}
void keyPressed() {
// If you press r, start or stop recording!
if (key == 'r' || key == 'R') {
background(0);
recording = !recording;
}
}
Turning your saved frames into a quicktime movie
Open Processing
Open your sketch or create a new sketch
Under the Tools menu select Movie Maker
Drag the folder of images onto the appropriate field
//from http://amnonp5.wordpress.com/2012/01/28/25-life-saving-tips-for-processing/
boolean blinker;
int timer = -3000;
void setup() {
size(700,400);
textFont(createFont("Arial",30));
}
void draw() {
background(255);
fill(0);
text("you are in frame: " + frameCount,50,50);
text(millis()/1000 + " seconds have passed since the start", 50,100);
text("this text will be here forever",50,150);
if (frameCount < 500) {
text("this text will be here for 500 frames",50,200);
}
if (frameCount > 800) {
text("this text will be here from 800 frames onwards",50,200);
}
if (millis() < 8000) {
text("this text will be here the first 8 seconds",50,250);
}
if (millis() > 12000) {
text("this text will be here from 12 seconds onwards",50,250);
}
if (frameCount % 12 == 0) { blinker = !blinker; }
if (blinker) {
text("this text will blink",50,300);
}
if (millis() - timer < 3000) {
text("this text will be here 3 secs after pressing a key",50,350);
}
}
void keyPressed() {
timer = millis();
}
Fader f;
int ltc;
boolean stopped=true;
int randomInterval;
Fader[] faders=new Fader[] {
new RightFade(),
new CrossFade(),
new RandomBlockFade()
};
int minDelay=5000;
int maxDelay=12000;
float SPEED=120.0; // smaller = faster animation, larger= slower animation
PImage[] carousel; // carousel of images, as an array
int carouselShowing; // index of start image in carousel
int carouselNext;
int carouselType=0;
String[] loadFilenames;
int counter, fileCount;
int nextImage;
void setup() {
size(650, 433, P2D);
loadFilenames();
carousel = new PImage[loadFilenames.length]; // maximum of 10.000 images
loadPhotos(); // all existing images are loaded in setup
fileCount = loadFilenames.length;
randomInterval=(int)random(minDelay, maxDelay);
setImageNum(0);
background(0);
}
void draw() {
if (millis()-ltc>randomInterval) {
ltc=millis();
setImageNum(1);
}
if (!stopped) {
if (frameCount<=SPEED) {
// show next frame of the animation
f.animateFade(float(frameCount)/SPEED);
}
else {
// show end image
f.endFade();
}
// draw current state of transition effect
f.draw();
}
}
void keyPressed() {
//RIGHT and left go forward and back through the carosel
if (key=='1') {
carouselType=1;
}
if (key=='2') {
carouselType=2;
}
if (key=='0') {
carouselType=0;
}
if (key == CODED) {
if (keyCode == RIGHT) {
nextImage=checkNextImage(carouselShowing+1);
carouselNext=(nextImage)%carousel.length;
f.setImages(carousel[carouselShowing], carousel[carouselNext]);
carouselShowing=carouselNext;
f.startFade();
randomInterval=(int)random(minDelay, maxDelay);
}
else if (keyCode == LEFT) {
nextImage=checkNextImage(carouselShowing-1);
carouselNext=(nextImage)%carousel.length;
f.setImages(carousel[carouselShowing], carousel[carouselNext]);
carouselShowing=carouselNext;
f.startFade();
randomInterval=(int)random(minDelay, maxDelay);
}
if (keyCode == UP) {
nextImage=checkNextImage(carouselShowing+(int)random(carousel.length));
carouselNext=(nextImage)%carousel.length;
f.setImages(carousel[carouselShowing], carousel[carouselNext]);
carouselShowing=carouselNext;
f.startFade();
randomInterval=(int)random(minDelay, maxDelay);
}
}
}
void mousePressed() {
stopped=!stopped;
}
void setImageNum(int offset) {
frameCount=0;
switch(carouselType) {
case 0:
f=faders[1];
SPEED=200;
break;
case 1:
f=faders[0];
SPEED=50;
break;
case 2:
f=faders[2];
SPEED=100;
break;
}
nextImage=checkNextImage(carouselShowing+offset);
carouselNext=(nextImage)%carousel.length;
f.setImages(carousel[carouselShowing], carousel[carouselNext]);
carouselShowing=carouselNext;
f.startFade();
randomInterval=(int)random(minDelay, maxDelay);
}
int checkNextImage(int n) {
int img;
if (n>=0) {
img=n;
}
else if (n==carousel.length-1) {
img=0;
}
else {
img=carousel.length-1;
}
return img;
}
void checkNew() {
loadFilenames();
if (loadFilenames.length > fileCount) {
loadPhotos();
fileCount = loadFilenames.length;
println("fileCount: " + fileCount);
} // only call loadPhotos if there are new images
}
void loadFilenames() {
java.io.File folder = new java.io.File(dataPath("")); // reads files from data folder
java.io.FilenameFilter imgFilter = new java.io.FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".jpg") || name.toLowerCase().endsWith(".png");
}
};
loadFilenames = folder.list(imgFilter);
}
void loadPhotos() {
for (int i = fileCount; i < loadFilenames.length; i++) { // only load new images
carousel[i] = loadImage(loadFilenames[i]);
}
println("fileCount: " + fileCount);
println("loadFilenames.length: " + loadFilenames.length);
}
class Fader {
PImage img1; // start image
PImage img2; // end image
PGraphics alphamask; // monochrome image mask
public void setImages(PImage im1,PImage im2) {
img1=im1;
img2=im2;
alphamask=createGraphics(img1.width,img1.height);
startFade();
}
/**
* called to initialise fade. This default implementation starts
* with a black mask. Subclasses can override this to do other initialisation.
*/
public void startFade() {
alphamask.beginDraw();
alphamask.fill(0);
alphamask.stroke(0);
alphamask.rect(0,0,img1.width,img1.height);
alphamask.endDraw();
}
/**
* called to end the fade. This default implementation creates a 100% white mask.
* May not be needed, but I've had some problems with rounding errors
* and arc drawing leaving gaps. Calling this will
* guarantee you see 100% final image.
*/
public void endFade() {
alphamask.beginDraw();
alphamask.fill(255);
alphamask.stroke(255);
alphamask.rect(0,0,img1.width,img1.height);
alphamask.endDraw();
}
/**
* called for each frame of the animation. pass in the percentage (0.0-1.0) of the effect.
* this should be overridden for each effect subclass.
*/
public void animateFade(float percent) {
;
}
/**
* Renders blended images. You shouldn't need to override this.
*/
public void draw() {
loadPixels();
int w=img1.width;
for (int ix=0;ix<img1.pixels.length;ix++) {
int y=ix/w;
int x=ix%w;
int col1=img1.pixels[ix];
int r1=(col1&0xFF0000)>>16;
int g1=(col1&0xFF00)>>8;
int b1=(col1&0xFF);
int col2=img2.pixels[ix];
int r2=(col2&0xFF0000)>>16;
int g2=(col2&0xFF00)>>8;
int b2=(col2&0xFF);
int colmask=alphamask.pixels[ix]^0xFFFFFFFF;
int level=(colmask&0xFF); // use blue channel
float lev=(float)level/256.0;
int rr=(int)((float)(r1*lev)+(float)(r2*(1-lev)));
int gg=(int)((float)(g1*lev)+(float)(g2*(1-lev)));
int bb=(int)((float)(b1*lev)+(float)(b2*(1-lev)));
pixels[ix]=0xFF000000|rr<<16|gg<<8|bb;
}
updatePixels();
}
}
class CrossFade extends Fader {
// simple crossfade. Mask is gradually changed from black (first image)
// to white (second image)
public void animateFade(float percent) {
alphamask.beginDraw();
alphamask.fill(255*percent);
alphamask.stroke(255*percent);
alphamask.rect(0,0,img1.width,img1.height);
alphamask.endDraw();
}
}
class RightFade extends Fader {
// second image is introduced from the right
public void animateFade(float percent) {
alphamask.beginDraw();
alphamask.fill(255);
alphamask.stroke(255);
alphamask.rect(img1.width-(img1.width*percent),0,img1.width-(img1.width*percent),img1.height);
alphamask.endDraw();
}
}
class RandomBlockFade extends Fader {
// second image is introduced using random 8x8 pixel blocks
boolean[][] used;
public void startFade() {
used=new boolean[200][200];
super.startFade();
}
public void animateFade(float percent) {
int numcells=(img1.height/4)*(img1.width/4);
if (percent==0.0f) used=new boolean[200][200];
for (int i=0;i<(int)((float)numcells*percent);i++) {
int cellx=(int)random((img1.width/4.0)+1);
int celly=(int)random((img1.height/4.0)+1);
used[celly][cellx]=true;
}
alphamask.beginDraw();
alphamask.fill(255);
alphamask.stroke(255);
for (int y=0;y<=img1.height/4;y++) {
for (int x=0;x<=img1.width/4;x++) {
if (used[y][x]) {
alphamask.fill(255);
alphamask.stroke(255);
} else {
alphamask.fill(0);
alphamask.stroke(0);
}
alphamask.rect(x*4,y*4,4,4);
}
}
alphamask.endDraw();
}
}