Friday, June 24, 2011

JAITools version 1.2.0 and Jiffle version 0.2.0 released

JAITools version 1.2.0 and Jiffle version 0.2.0 are now available. These are the first versions under the new org.jaitools domain and the first to be covered by Simplified BSD licence (aka BSD-2)

If you use Maven as your build tool, see the notes below on upgrading to the new versions.

You can download binaries manually from Maven Central directly at http://repo1.maven.org/maven2/org/jaitools/ or by using the Maven Search interface.

JAITools
Version 1.2.0 is a minor release with a large number of fixes and improvements, better unit test coverage and more comprehensive javadocs. In addition, there are the new image iterator classes SimpleIterator and WindowIterator which were previewed here in earlier posts.

To download the JAITools source code using Subversion:
    svn co http://jaitools.googlecode.com/svn/tags/1.2.0 jaitools-1.2.0
You can browse the API docs at: http://jaitools.org/docs/jaitools/stable/apidocs/

Jiffle
Version 0.2.0 is also a minor release aligned with JAITools 1.2.0.

To download the Jiffle source code using Subversion:
    svn co http://jiffle.googlecode.com/svn/tags/0.2.0 jiffle-1.2.0
You can browse the API docs online at: http://jaitools.org/docs/jiffle/stable/apidocs/The draft Jiffle user guide is here: http://jaitools.org/docs/jiffle/latest/userguide/html/

Upgrading from previous versions
  1. In your source code, edit all JAITools and Jiffle import statements and add the org.prefix. For example:
    import jaitools.imageutils.ROIGeometry;
    becomes...
    import org.jaitools.imageutils.ROIGeometry;
  2. If use you Maven as your build tool, edit your project pom.xml file and change the groupId for all JAITools and Jiffle modules from com.googlecode.jaitools to org.jaitools. For example, the dependency for the jt-utils module will now look like this...
    <dependency>
    <groupId>org.jaitools</groupId>
    <artifactId>jt-utils</artifactId>
    <version>1.2.0</version>
    </dependency>

Coming up next

The wiki on the JAITools Google Code site is sadly out of date, so the next item on the todo list is to replace it with Sphinx-based documentation at jaitools.org.

Meanwhile please try the new versions and give us your feedback via the mailing list or by tweeting to @JAITools.

Share and enjoy.

Tuesday, June 14, 2011

Hyphenectomy

I'm really not sure why I thought JAI-tools was a good name for the project, as opposed to just JAITools. Not only does the dash fail to serve any real purpose in the name, it also guaranteed a clash with package names. And because it seemed more natural for the project's Maven group Id to follow the package names ("jaitools") rather than the project name ("jai-tools") things went from dumb to dumber.

So, the time has come for a radical hyphenectomy (dash removal) consisting of the following changes:
  • A new project web site will be set up at http://jaitools.org. The existing API docs and Jiffle user guide have already been moved from http://jai-tools.org to the new domain.
  • The project's Google Code website is being moved from http://code.google.com/p/jai-tools to http://code.google.com/p/jaitools
  • The root package name and Maven groupId for both JAITools and Jiffle will be org.jaitools
  • This blog will move to http://jaitools.blogspot.com
The new Maven groupId and package names will take effect with the next release: version 1.2.0 for JAITools and version 0.2.0 for Jiffle, both of which are due before the end of this month (June 2011).

Update - 18 June 2011

All project sources have now been moved to the new Google Code site: http://code.google.com/p/jaitools/.

Thursday, June 2, 2011

JAI-tools and Jiffle go free-er

JAI-tools and Jiffle are now covered by the Simplified BSD licence. This applies to the forthcoming JAI-tools version 1.2 release, and immediately to all of the development sources in both projects.

The intention is simple: to encourage use of, and contribution to, both projects as much as possible.

Share and enjoy.

Wednesday, June 1, 2011

Next please ! Image iterators part 2

In the previous article the new SimpleIterator and WritableSimpleIterator classes were introduced. In this article, we'll look at some additional features of those classes and then take a peek at another new class: WindowIterator.

Sometimes size matters. If you are working with massive images it's important to make data access as efficient as possible. This is even more important when working with images over a network. SimpleIterator caters for this with its tile-wise traversal option...


RenderedImage myGreatBigImage = ...
Rectangle iteratorBounds = ...
int outside = 0;

// create an iterator that will visit each tile in turn
SimpleIterator iter = new SimpleIterator(myGreatBigImage, iteratorBounds,
outside, SimpleIterator.Order.TILE_X_Y);

// no special code is required when using the iterator in tile-wise mode
do {
Number sample = iter.getSample();
// do interesting things with data
...
while (iter.next());


With tile-wise traversal, the iterator first divides its bounding rectangle into sub-bounds according to the image's tile structure. When moved with the next() method, as in the above code snippet, the iterator will visit all pixels in a sub-bound before proceeding to the next. This minimizes the need to swap tiles in and out of memory or move them across a network.

You can also use random access in combination with tile-wise traversal as in this example...

SimpleIterator iter = new SimpleIterator(myGreatBigImage, iteratorBounds,
outside, SimpleIterator.Order.TILE_X_Y);

// We first sample a specified position
Number sample = iter.getSample(x, y, band);

// Now if we continue sequentially, the iterator will do tile-wise
// sampling of the image
while (iter.next()) {
sample = iter.getSample(band);
...
}


WindowIterator

Moving window algorithms are common in image processing. Many kernel-based analyses can be implemented as convolutions using JAI's Convolve operator or the more flexible JAI-tools MaskedConvolve operator (see also the JAI-tools KernelFactory class). However, algorithms which are more complex or involve probabilistic sampling of the values in the moving window are better handled by passing the moving window values to the client directly. The new WindowIterator class caters for this.

Consider the Voter Model algorithm in which, over many iterations, the value of each pixel in an image is replaced by a randomly selected value from its neighbourhood. Clint Sprott's excellent website has examples of this algorithm applied to ecological simulation and image reconstruction.

Below is a snippet adapted from a JAI-tools example program showing how WindowIterator can be used with a WritableSimpleIterator to implement the Voter Model algorithm (the complete example is available here).


// A WindowIterator gets values from the source image
Dimension winDim = new Dimension(3, 3);
Point keyElement = new Point(1, 1);
winIter = new WindowIterator(sourceImage, null, winDim, keyElement);
int[][] dataWindow = null;

// A WritableSimpleIterator to set values in the destination image
writeIter = new WritableSimpleIterator(destImage, null, null);

do {
// Get a 3x3 window of values from the source image
dataWindow = winIter.getWindow(dataWindow);

// Call a method which random selects a window position
// other than the key element
Point nbr = getRandomNbr(winDim, keyElement);

// Write the value of the selected neighbour to the
// destination image
writeIter.setSample(dataWindow[nbr.y][nbr.x]);

} while (winIter.next() && writeIter.next());


The bounds of a WindowIterator represent all positions that the data window's key element will traverse. If the bounds are equal to, or extend beyond, the image bounds, then some data window positions can lie outside the image. WindowIterator lets you specify an outside value to be returned for these positions...


// This iterator will return -1 for all cells that lie outside the image
WindowIterator iter = new WindowIterator(image, bounds, winDim, keyElement, -1);


If you're familiar with JAI's BorderExtender classes you'll note that this is equivalent to using a BorderExtenderConstant.

WindowIterator also allows you to set the X and Y step distances. In this example, the step distances are set to the window dimensions to down-sample the source image...

RenderedImage image = ...

Dimension winDim = new Dimension(3, 3);
Point keyElement = new Point(1, 1);
int xstep = 3;
int ystep = 3;

Rectangle iterBounds = new Rectangle(
image.getMinX() + 1, image.getMinY() + 1,
image.getWidth - 2, image.getHeight() - 2);

WindowIterator iter = new WindowIterator(image, iterBounds, winDim, keyElement,
xstep, ystep, 0);

do {
dataWindow = iter.getSample(dataWindow);
// extract desired summary from window and write to
// a destination image
...
} while (iter.next());

Monday, May 30, 2011

Next please ! Easier image iterators

The forthcoming JAI-tools version 1.2 will include several new image iterator classes. Here is a quick preview of two of them: SimpleIterator (read-only access) and WritableSimpleIterator (read-write access).

If you are used to working with the standard JAI RectIter class you probably have nested do-while loops burnt into your frontal cortex from having to write code like this countless times...
RectIter iter = ...
do {
do {
int value = iter.getSample();
// do something with value
} while (!iter.nextPixelDone());
iter.startPixels();
} while (!iter.nextLineDone());

In comparison, SimpleIterator is, well, simpler...
SimpleIterator iter = ...
do {
Number value = iter.getSample();
// do something with value
} while (iter.next());

The next() method takes care of both horizontal and vertical movement, plus it is always safe to call it speculatively. There is also a hasNext() method for convenience.

The comparison is more telling for code where you need to track the location of the image iterator. With RectIter you might write something like this...
RenderedImage image = ...
RectIter iter = ...
int x = image.getMinX();
int y = image.getMinY();
do {
do {
int value = iter.getSample();
x++ ;
// do something with value
} while (!iter.nextPixelDone());
iter.startPixels();
x = image.getMinX();
y++ ;
} while (!iter.nextLineDone());

But with SimpleIterator you can use the getPos() method...
RenderedImage image = ...
SimpleIterator iter = ...
do {
Number value = iter.getSample();
Point pos = iter.getPos();
// do something with value and position
} while (iter.next());

You might have noticed that SimpleIterator.getSample() returns a Number object rather than a primitive value. Unlike JAI's RectIter class, there are no separate getSampleFloat and getSampleDouble methods. Instead, the iterator returns image values that are either Integer, Float or Double class depending on the data type of the source image.

You can also use SimpleIterator as a replacement for JAI's RandomIter class. In fact, a SimpleIterator instance provides both sequential (X then Y) movement across an image via its next() method, plus random positioning with additional getSample methods as shown here...
// get the value of a specific position and band
int value = simpleIter.getSample(x, y, band).intValue();

// now continue from that position to the end of the iterator bounds
while (simpleIter.next()) {
value = simpleIter.getSample().intValue();
}


SimpleIterator also provides more flexible bounds handling. For example, you can set the bounds of the iterator to extend beyond those of the source image. When the iterator is positioned outside the image it will return an outside value which is set via the constructor...
// create an iterator that will return -1 when positioned outside the
// source image bounds
SimpleIterator iter = new SimpleIterator(myImage, iteratorBounds, -1);

This makes it easy to program applications that need to sample within a fixed bounding rectangle, which may or may not be contained within an image's bounds. There is no need to intersect rectangles or monitor positions in your own code.

WritableSimpleIterator provides the same methods as SimpleIterator together with the ability to set values in a writable image, either sequentially or for specified positions.

But wait - there's more ! JAI-tools version 1.2 will also include WindowIterator, to pass a client-defined moving window over an image, and ImageSetIterator, to sample multiple images simultaneously. We'll talk more about these in a subsequent article.

Tuesday, April 5, 2011

JAI-tools version 1.1.1 and Jiffle version 0.1.0 released

The JAI-tools team is pleased to announce the combined release of new versions of JAI-tools and Jiffle. This is the first release since Jiffle moved into a separate project with its own versioning (see previous post).

The new versions are now available from the Maven Central repository and mirror sites.

You can checkout the sources from:
http://jai-tools.googlecode.com/svn/tags/1.1.1
http://jiffle.googlecode.com/svn/tags/0.1.0

To search for particular changes of interest go to the issue tracker for each project.

Thanks to Andrea Aime and Daniele Romagnoli for their work on this release, and also Ian Turton and Manuel Bossant for contributions and bug spotting.

JAI-tools version 1.1.1

This is a minor release which includes bug fixes and improvements, but also some new features. Notable items:
  • ROIGeometry now has more methods implemented and improved performance.
  • Problems with clipping and setting rendering hints have been fixed in the DiskMemImageGraphics class.
  • KernelFactory has been expanded and can now generate many standard kernel types including cosine, Gaussian, Epanechnikov and quartic.
  • Improvements to the utility Swing widgets.
  • A new CompareOp class for comparison of double and float values taking into account absolute or proportional tolerance.

Jiffle version 0.1.0

This is the first release of the Jiffle scripting language under its own version numbering. The new jars are jt-jiffle-language-0.1.0.jar and jt-jiffle-demo-0.1.0.jar.

The main change from the version that was included with JAI-tools 1.1.0 is support for user-defined coordinates. This separates the bounds and resolution of the processing area from those of the source and destination images. It means that within your Jiffle script, you can work with whatever type of coordinates are best suited to your application, e.g. geographic, proportional, or arbitrary cartesian coordinates. When running a script, CoordinateTransform objects are used to convert between user coordinates and pixel positions in each source and destination image.

The separation of processing and image coordinates can be handy even when you are working directly with pixel positions. You can use it to deal with non-overlapping source and destination images, or as a device to sub-sample or over-sample source images.

As well as the new coordinate support, there have been some small extensions to Jiffle's syntax and a general tidy-up of the code base and javadocs.

Share and enjoy.

Tuesday, March 22, 2011

Jiffle leaves home to grow up

Although it's usually the other way around (grow up then leave home) sometimes things don't turn out as planned...

For Jiffle, the scripting language developed as part of JAI-tools, what was originally planned was compatibility with the r.mapcalc raster algebra language used in GRASS GIS, but recently we decided that this was too limiting and it would be better to set Jiffle free and have its development driven purely by our brilliant ideas (plus the moderating influence of user feedback).

Like all great ambitions, this one quickly ran aground on the rocks of practical constraint. Being a module in a Maven-based project, Jiffle had the same version number as all of the other JAI-tools modules, but this didn't fit well with allowing Jiffle's syntax and code-base to be more fluid (ie. lots of changes breaking backwards-compatibility). So it was decided to separate Jiffle out from the JAI-tools project.

Jiffle now has its own site: http://code.google.com/p/jiffle/ and it's been re-versioned to 0.1.x to make it clear to users that substantial changes can be expected. Despite leaving home, Jiffle will retain its close relationship to JAI-tools, with the same project team developing both.

Unfortunately, this has created a certain amount of version chaos. At Maven Central you can find:
  • jt-jiffle-1.1.0.jar (as part of the most recent JAI-tools release)
  • jiffle-1.0.1.jar (from the previous release before the "jt-" prefix was adopted)
  • And soon: jt-jiffle-language-0.1.0.jar (the new jar name being required to avoid future clashes with previous versions)
It's hard to see how we could have made it much more confusing.

Here's what to do:
  • For JAI-tools version 1.1.0, use jt-jiffle-1.1.0
  • With later JAI-tools releases, swap over to the most recent version of jt-jiffle-language
If you you use Maven as your build tool it will cut through much of this confusion for you because the dependency relationship between different versions of JAI-tools and Jiffle will be contained in each project's pom.xml file.

The next post will show off some of the new Jiffle language features to prove that all of this chaos has been worth it :)

Monday, March 7, 2011

JAI-tools version 1.1.0

The JAI-tools project team is pleased to announce the release of version 1.1.0 of the library. This is a bumper issue with many new features plus major improvements to existing features. Highlights (described below) include new image operators Contour, Vectorize and VectorBinarize; a new ROI class capable of handling massive images; and a performance boost for the Jiffle scripting language.

The release is now available from the Maven Central repository and mirror sites. Maven users should read the notes below (Library setup) about new module names and the option of using a single jar.

You can checkout the sources for this release from:

http://jai-tools.googlecode.com/svn/tags/1.1.0

To search for particular changes of interest go to the issue tracker.

Many thanks to team members Andrea Aime, Andrea Antonello and Simone Giannecchini for all of their work and advice over the last year.

Summary of new features and changes

New image operators

Contour

Generates vector contours from raster image values. The contour levels can be specified explicitly or as the interval between levels. Selective contouring can be done by defining particular image values or ranges of values as NoData to be ignored by the operator. The generated contours are returned as JTS LineString objects, suitable for plotting as well as further manipulation or analysis. Here are a couple of examples of the operator in action courtesy of GeoSolutions:


Vectorize

Generates vector boundaries (as JTS Polygons) for regions of uniform value in a raster image. This complements the JAI-tools Regionalize and RangeLookup operators. Here is an example, where an image has first been classified into two uniform ranges using RangeLookup and then vectorized into polygons using Vectorize:

VectorBinarize

An alternative to the standard JAI Binarize operation. The destination image is backed by a JTS Geometry object rather than a raster. This makes it possible to binarize massive images with only small memory usage.

New ROI class

The new ROIGeometry class can be used as a replacement for the standard JAI ROIShape class. It is backed by a JTS Geometry object rather than an image to minimize memory overhead and it works in conjunction with the VectorBinarize operator, making it possible to define ROIs over massive image areas. It also offers the choice of using pixel corner or center coordinates which is particularly useful for geospatial applications.

Jiffle

The Jiffle image scripting language has been almost completely rewritten for this new version, as previewed in previous posts here and here.

It's faster

Jiffle scripts are now translated to Java source and then compiled to executable bytecode using the Janino in-memory compiler. As a result, scripts now run hundreds of times faster than was the case in version 1.0. The generated Java source can be saved for later use and the compiled objects can be used as any other Java class.

It's easier

A new JiffleBuilder class makes it easier to compile and run scripts with a minimum of key strokes. It can also create a destination image for you ready to receive the results of the script.

It's multi-tasking

The JiffleExecutor class allows you to run one or more Jiffle scripts on background threads. The progress of each task can be monitored and results are passed back to the caller via a simple event system.

It has more bits

The Jiffle language itself has been extended and now provides support for multi-band source images, scoped variables, loop constructs and simple lists.

And it's coming to a program near you

Jiffle can be integrated into applications as an analysis engine. It has been used in JGrass and is about to appear in the upcoming spatial toolbox OmsBox in the uDig GIS application.


As well as Jiffle, OmsBox will include many other features from JAI-tools such as the contour extractor:



To learn more about Jiffle, have a look at the new collection of example programs.

Library setup

Module names

All module names are now prefixed with "jt-" to make it easier to spot them when you're working with a large number of other dependencies. If you use Maven, this means you'll need to edit both the name and the version of JAI-tools modules in your existing pom.xml files.

One jar fits all

You now have the option of using a single jar for JAI-tools. Maven users just need to include jt-all as a dependency in the pom.xml file. If you don't use Maven you can download and add jt-all-1.1.0.jar to your project manually. This combined jar includes all JAI-tools modules other than jt-demo (the example applications).

Monday, February 21, 2011

Jiffle plays the Game of Life


After showing off with fractals in the last Jiffle demo, it seemed only natural to delve back in time for another classic to illustrate new features and uses of the language. And nothing could be more classic than John Conway's Game of Life: a cellular simulation with simple rules that can display exceptionally complex behaviour. If you're not familiar with Life, this Wikipedia article is a good place to start. You can also marvel at the compendious collection of Life patterns at LifeWiki:

The Java Swing program shown in the screen-shot above uses a Jiffle runtime object as a simulation engine to play Life. Two different Jiffle scripts are used: one which simulates a world with edges; and a second where the world is a toroid, ie. opposite edges of the image are joined to form a continuous surface. In both scripts the world is an image where an unoccupied location is represented by pixel value 0 and an occupied location by pixel value 1.

Here is the entire script for the world with edges:

options { outside = 0; }

n = 0;
foreach (iy in -1:1) {
foreach (ix in -1:1) {
n += world[ix, iy];
}
}

n -= world;
nextworld = (n == 3) || (world && n==2);

The expression world[ix, iy] accesses a relative neighbour location. For example world[-1, 1] would get the value of a pixel at (x-1, y+1) where x and y are the ordinates of the current pixel.

The two foreach loops use integer sequence syntax, startValue:endValue, to iterate over the 3x3 neighbourhood centred on the current pixel and count the number of occupied cells (those with a value of 1). The rules of Life are expressed only in terms of the number of neighbouring cells occupied, so we adjust the value of n by subtracting the value of the current pixel.

The options block at the top of the script sets a value to be returned for any neighbour positions that are beyond the bounds of the image. Without this option, the runtime object would throw an Exception at the very first pixel when trying to access the relative neighbour position world[-1, -1].

The final line of the script expresses all of the Game of Life rules in a single statement ! It uses naked conditional statements which return 1 or 0.

A second Jiffle script provides an alternative version of the simulation, where the image representing the world is treated as a toroid:

n = 0;
foreach (iy in -1:1) {
yy = y() + iy;
yy = if (yy < 0, height() - 1, yy);
yy = if (yy >= height(), 0, yy);

foreach (ix in -1:1) {
xx = x() + ix;
xx = if (xx < 0, width()-1, xx);
xx = if (xx >= width(), 0, xx);
n += world[$xx, $yy];
}
}

n -= world;
nextworld = (n == 3) || (world && n==2);


This script works with absolute rather than relative neighbour positions. These are indicated by the $ prefix. When a neighbour position is beyond an edge, it is adjusted to the corresponding position at the opposite edge. Note that we don't need the outside option in this script.

The Game of Life is an iterative simulation where the output for time t becomes the input for time t+1. To accomplish this, the demo program caches the runtime objects compiled from the Jiffle scripts, and uses them repeatedly with two images which are represented by the variables world and nextworld in the scripts. These images are simply swapped between source and destination roles at each time step as shown in this code fragment...

activeRuntime.setSourceImage(WORLD_NAME, curWorld);
activeRuntime.setDestinationImage(NEXT_WORLD_NAME, nextWorld);
activeRuntime.evaluateAll(null);

TiledImage temp = curWorld;
curWorld = nextWorld;
nextWorld = temp;

You can view and download the complete source code for this program from the JAI-tools web site.

Monday, February 14, 2011

Jiffle meets Mandelbrot


The Jiffle scripting language has been getting some new bells and whistles recently. While the idea is still to keep the language small and simple, by adding a few extra constructs it becomes much more flexible.

Above is the JiffleDemo application showing a script that uses two of these new constructs, scoped variables and loops, to generate a binary image of the Mandelbrot set. Below is the script itself (it is one of the examples distributed with JAI-tools).

The "init" block is where you declare variables that you want to remain in scope throughout processing. Jiffle calls these image-scope variables. Variables declared outside this block are termed pixel-scope, ie. their values are discarded after each pixel is processed. In the Java runtime class that the Jiffle compiler creates, the image-scope variables are class fields while the pixel-scope variables are local to the evaluate method called to process each destination image pixel. The runtime class is also provided with a getter method for the image-scope variables so you can retrieve them after running the script. You could use this, for instance, to count pixels that are in a certain value range.

The script below uses an until-loop (lifted from Ruby) for the iterative calculation. Jiffle also offers a while-loop and I'm musing about adding some kind of for-loop syntax as well.

/*
* An example Jiffle script: draws a binary
* image of the Mandelbrot set. Adapted from
* C code at http://warp.povusers.org/Mandelbrot/
*
* Author: Michael Bedward
*/

/* We declare variables that we want to remain
* in scope between pixels in the 'init' block.
* The functions width() and height() return
* the dimensions of the destination area.
*/
init {
MaxIter = 30;
MinRe = -2.0;
MaxRe = 1.0;
MinIm = -1.2;
MaxIm = MinIm + (MaxRe-MinRe) * height() / width();
Re_scale = (MaxRe-MinRe)/(width()-1);
Im_scale = (MaxIm-MinIm)/(height()-1);
}

/* Calculations performed for each pixel.
* The functions x() and y() return current
* pixel coordinates.
*/
c_im = MaxIm - y()*Im_scale;
c_re = MinRe + x()*Re_scale;

Z_re = c_re;
Z_im = c_im;

outside = 0;
n = 0;

/* Jiffle has an 'until' loop construct */
until (n >= MaxIter || outside) {
Z_re2 = Z_re*Z_re;
Z_im2 = Z_im*Z_im;
outside = if (Z_re2 + Z_im2 > 4);
Z_im = 2*Z_re*Z_im + c_im;
Z_re = Z_re2 - Z_im2 + c_re;
n++ ;
}

/* The variable 'result' represents the
* destination image (you can use any name
* you like in your own scripts).
*/
result = outside;

As an aside, I recall using much the same algorithm, though in FORTRAN, to generate Mandelbrot set images on an 80286 PC last century. Some people never change...

Wednesday, February 9, 2011

Continuous JAI-tools builds

Now that the project is getting bigger and (gasp) actually being used it was time to get more organized about our build process, or rather, to actually have one. To date we've relied on an ad hoc process of people checking out the sources, building them on their local system, and then reporting that Michael has broken the build again.

Now, courtesy of the kind folks at OpenGeo, in particular Justin Deoliveira, JAI-tools has entered the world of continuous integration. OpenGeo's Hudson server now builds the development code (ie. sources from trunk the project's subversion repository) and you can check the status of the builds at http://hudson.opengeo.org/hudson/view/jai-tools/. If you are subscribed to the project discussion list you will also be sent notices of any build failures.

Thanks to Justin and Andrea Aime for organizing all of this.

Thursday, January 13, 2011

Images in a jiffy: speeding up Jiffle with Janino

Jiffle is a scripting language for raster algebra dreamed up by myself and Andrea Antonello. You can use it to create, combine and analyse raster (pixel) images. It's based on the r.mapcalc language for map calculations in the GRASS GIS program.

The idea of Jiffle is to let you concentrate on the interesting bits rather than having to write the incredibly tedious boiler plate code that is normally required to work with image data using Java. The image here of a simple trigonometric function was created with this script...
    xc = width() / 2
    yc = height() / 2
    dx = (x()-xc)/xc
    dy = (y()-yc)/yc
    d = sqrt(dx^2 + dy^2)
    outImg = sin(8 * PI * d)

The Jiffle parser, developed using ANTLR, converts a script like the one above into a tree representation of the expressions (Abstract Syntax Tree or AST). Up until now, running the script involved walking this tree multiple times (once per destination image pixel) and executing the expression like an interpreter. While this worked, it was much too slow to process large images.

Enter Janino, which advertises itself (quite accurately) as a "super-small, super-fast Java™ compiler". One of things you can do with Janino is to compile source and load the resulting bytecode in-memory. To apply this to Jiffle, I first replaced the ANTLR grammar for the run-time tree walker with one that translates an AST into a Java method body. For example, the script above is translated to this...

double xc=_width / 2.0;
double yc=_height / 2.0;
double dx=(_x - xc) / xc;
double dy=(_y - yc) / yc;
double d=Math.sqrt(Math.pow(dx, 2.0) + Math.pow(dy, 2.0));
writeToImage("out", _x, _y, _band, Math.sin(25.132741228718345 * d));

Next, I created a new interface JiffleRuntime and a template for an implementing class that looks like this...

import jaitools.jiffle.runtime.JiffleRuntime;

import java.awt.image.RenderedImage;
import java.awt.image.WritableRenderedImage;
import java.util.HashMap;
import java.util.Map;
import javax.media.jai.iterator.RandomIter;
import javax.media.jai.iterator.RandomIterFactory;
import javax.media.jai.iterator.WritableRandomIter;

public class JiffleRuntimeImpl implements JiffleRuntime {

/*
* Note not using generics here because they are not
* supported by Janino.
*/
private Map images = new HashMap();
private Map readers = new HashMap();
private Map writers = new HashMap();

private double _width;
private double _height;

public void evaluate(int _x, int _y, int _band) {
// COMPILER_BREAK

throw new UnsupportedOperationException("Method body to be provided by Jiffle compiler");

// COMPILER_RESUME
}

public double readFromImage(String imageName, int x, int y, int band) {
RandomIter iter = (RandomIter) readers.get(imageName);
return iter.getSampleDouble(x, y, band);
}

public void writeToImage(String imageName, int x, int y, int band, double value) {
WritableRandomIter iter = (WritableRandomIter) writers.get(imageName);
iter.setSample(x, y, band, value);
}

public void setDestinationImage(String imageName, WritableRenderedImage image) {
images.put(imageName, image);

if (images.size() == 1) {
_width = image.getWidth();
_height = image.getHeight();
}

writers.put(imageName, RandomIterFactory.createWritable(image, null));
}

public void setSourceImage(String imageName, RenderedImage image) {
images.put(imageName, image);
readers.put(imageName, RandomIterFactory.create(image, null));
}

}

The Jiffle compiler inserts the generated statements into the evaluate method of this class...

public void evaluate(int _x, int _y, int _band) {
double xc=_width / 2.0;
double yc=_height / 2.0;
double dx=(_x - xc) / xc;
double dy=(_y - yc) / yc;
double d=Math.sqrt(Math.pow(dx, 2.0) + Math.pow(dy, 2.0));
writeToImage("out", _x, _y, _band, Math.sin(25.132741228718345 * d));
}

Now we have the run-time class source as a String in memory, we compile it with Janino's SimpleCompiler class and retrieve the resulting executable bytecode as shown here...

SimpleCompiler compiler = new SimpleCompiler();
compiler.cook(runtimeSource);
Class clazz = compiler.getClassLoader().loadClass(PACKAGE_NAME + "." + RUNTIME_CLASS_NAME);
runtimeInstance = (JiffleRuntime) clazz.newInstance();

And voila ! The Jiffle script has now been compiled into a form that will run at the speed of the JVM, hundreds of time faster than the original tree walking approach.

Janino doesn't handle generic collections or var-arg method calls so some work-arounds were required in the parser grammars and Jiffle's run-time support classes to deal with this. For example, instead of generating this source...

double foo = JiffleFunctions.median(x1, x2, x3, x4, x5);

We change the median method to expect a Double array and have the compiler generate this...

double foo = JiffleFunctions.median(new Double[]{x1, x2, x3, x4, x5});