Subscribe to our mailing list

Monday, February 01, 2010

Procedural Paint in Java: Perlin noise

A few days ago, I showed how to implement java.awt.Paint in a way that lets you vary the paint appearance according to the x-y position of a point onscreen -- in other words, treating Paint as a procedural texture. It turns out to be pretty straightforward. Implementing the Paint interface means providing an implementation for Paint's one required method, createContext():

Most of the formal parameters are hints and can be ignored. Note that the createContext()method returns a java.awt.PaintContext object. PaintContext is an interface, so you have to implement it as well, and this (it turns out) is where the real action occurs. The methods of the PaintContext interface include:

The dispose() method releases any resources that were allocated by the class. In many cases, you'll allocate nothing and thus your dispose method can be empty. The getColorModel() method can, in most cases, be a one-liner that simply returns ColorModel.getRGBdefault(). Where things get interesting is in getRaster(). That's where you have the opportunity to set pixel values for all the pixels in the raster based on their x-y values.

It turns out to be pretty easy to implement Perlin noise in custom Paint; see the 100 lines of code shown below. Note that in order to use this code, you need the class ImprovedNoise.java, which is a nifty reference implementation of Perlin noise provided by Ken Perlin here.

The code should be self-explanatory. There are two constructors; both allow you to pick the primary and secondary colors for the texture, but one includes an AffineTransform, whereas the other doesn't. If you use the constructor with the transform, you can scale (or rotate, etc.) the Perlin noise to suit your needs. To achieve the "cloudy" look, the text at the top of this post uses a scaling factor of .06 in x and .05 in y, per the script below. Note that to run the following script, it helps if you have a copy of ImageMunger, the tiny Java app I wrote about a couple weeks ago. ImageMunger is a very simple command-line application: You pass it two command-line arguments, namely a file path pointing at a JPEG or other image file, and a file path pointing at a JavaScript file. ImageMunger opens the image in a JFrame and executes the script. Meanwhile, it also puts two global variables in scope for your script to use: Image (a reference to the BufferedImage object) and Panel (a reference to the JComponent that paints the image). Be sure you have JDK6.

/* perlinText.js* Kas Thomas* 1 February 2010* Public domain.** Run this file using ImageMunger:* http://asserttrue.blogspot.com/2010/01/simple-java-class-for-running-scripts.html*/