-
Notifications
You must be signed in to change notification settings - Fork 37
Jiffle introduction
Jiffle is a simple scripting language to work with raster images. Its main aim is to let you get more done with less code.
To illustrate what we mean by that, let's compare a Java method for drawing a simple 3-D mathematical function with an equivalent Jiffle script. The function we'll use is this:
z_{x y} = sin( 8\pi D_{x y} )
It produces a set of concentric sinusoidal waves which emanate from the image center or, more poetically: ripples on the sunlit surface of a still pond...
Here is the Java code to plot the function. It uses a JAI iterator to set pixel values. We'll omit the import statements and just concentrate on the method itself (full code available in the repository):
public void createRipplesImage(WritableRenderedImage destImg) {
// image dimensions
final int width = destImg.getWidth();
final int height = destImg.getHeight();
// first pixel coordinates
int x = destImg.getMinX();
int y = destImg.getMinY();
// center pixel coordinates
final int xc = x + destImg.getWidth() / 2;
final int yc = y + destImg.getHeight() / 2;
// constant term
double C = Math.PI * 8;
WritableRectIter iter = RectIterFactory.createWritable(destImg, null);
do {
double dy = ((double) (y - yc)) / yc;
do {
double dx = ((double) (x - xc)) / xc;
double d = Math.sqrt(dx * dx + dy * dy);
iter.setSample(Math.sin(d * C));
x++ ;
} while (!iter.nextPixelDone());
x = destImg.getMinX();
y++;
iter.startPixels();
} while (!iter.nextLineDone());
}
Now here is the equivalent Jiffle script:
init {
// image centre coordinates
xc = width() / 2;
yc = height() / 2;
// constant term
C = M_PI * 8;
}
dx = (x() - xc) / xc;
dy = (y() - yc) / yc;
d = sqrt(dx*dx + dy*dy);
destImg = sin(C * d);
Compared to the Java method, the Jiffle script:
- is much shorter
- is easier to read because the algorithm isn't obscured by lots of boiler-plate code
- uses no loops!
That last feature is what enables Jiffle scripts to be so concise. In Jiffle, you don't write code to iterate over your source and destination images. Instead, you specify how to calculate the value of an individual pixel and the Jiffle runtime system then applies that calculation over the whole image.
Now, some readers might cry foul at the above comparison because although we presented the Jiffle script, we didn't show the necessary Java code to actually run it. To be fair, we didn't show the import statements and calling code necessary for the Java method either, but in the interest of even-handedness, here is one way to run that script within a Java program:
JiffleBuilder builder = new JiffleBuilder();
// These chained methods read the script from a file,
// create a new image for the output, and run the script
builder.script(scriptFile).dest("destImg", 500, 500).run();
RenderedImage result = builder.getImage("destImg");
Jiffle is still quite a new language and some of the features that we eventually hope to support are not in there yet. There are also some constraints imposed by the nature of the Jiffle run-time system.
- Destination images must be data type double (Java DataBuffer.TYPE_DOUBLE). Jiffle does all calculations using double values, regardless of the type(s) of source images involved.
- Jiffle run-time objects iterate through source and destination images by X-ordinate (column), then Y-ordinate (row). Algorithms that require a different iteration order, such as the diamond-square method for generating fractal surfaces ^2 will either be impossible to implement in Jiffle or just a lot less work to write directly in Java.