Java Advanced Imaging Operators
Here are a couple of JAI operators which I've written for various purposes and which you may find useful. Feel free to make any use whatsoever of these classes.
The Mosaic operator tiles together a set of images to make one large image. I wrote this for displaying maps which came as a set of TIFF images, each 4000 pixels square. The parameters to the operator are the number of rows and columns in the tile grid. The tiles themselves are the sources to the operator in left-to-right, top-to-bottom order. All tiles must have the same color and sample models as well as the same internal tile size. If your tile grid has gaps in it, use the constant operator to fill them in, setting the ImageLayout to be the same as one of the real source tiles using the format operator.
This operator takes a single parameter which is the name of an XML file which defines a JAI graph. This is a useful operator for testing as it allows you to set up JAI graphs without compiling code. It could also be useful as the basis for an image server or a compositing application. I wrote this as a quick hack for debugging purposes, and I would not claim it to be in any way well engineered or complete, but I find it useful and I hope that it will give someone the idea to do this properly.
As an extra bonus, I've written a codec which will recognize XML files. This allows JAI applications to open these files using the ordinary "fileload" or "url" operators. The application must first register the codec and operator, but this is simple. For the XML file to be recognised by the XML codec, it must start with the characters "<?xml".
Before defining the syntax, here's a couple of examples to give you the idea:
1) This is just about the simplest possible XML file. This just creates a "fileload" operator with parameter "foo.tiff".
<?xml version="1.0"?> <jaiop> <image op="fileload" filename="foo.tiff"/> </jaiop>
2) Adding two images together
<?xml version="1.0"?> <jaiop> <image xj:op="add"> <image xj:op="fileload" filename="foo.tiff"/> <image xj:op="fileload" filename="bar.tiff"/> </image> </jaiop>
3) Adding an image to a rotated image of itself. This is an example of creating a DAG instead of a tree.
<?xml version="1.0"?> <jaiop> <image xj:op="add"> <image xj:name="the-image" xj:op="fileload" filename="foo.tiff"/> <image xj:op="rotate" angle="0.1"/> <imageref xj:name="the-image"> </image> </image> </jaiop> 4) Using the mosaic operator: <?xml version="1.0"?> <jaiop> <image xj:op="mosaic" rows="2" cols="2"> <image xj:op="fileload" filename="nw.tiff"/> <image xj:op="fileload" filename="ne.tiff"/> <image xj:op="fileload" filename="sw.tiff"/> <image xj:op="fileload" filename="sw.tiff"/> </image> </jaiop>
The DTD for the XML file looks like this:
<!ELEMENT jaiop (image+)> <!ELEMENT image (image* imageref* property*)> <!ATTLIST image xj:name CDATA xj:op CDATA ...plus parameters required by the operator > <!ELEMENT imageref> <!ATTLIST imageref xj:name CDATA #REQUIRED > <!ELEMENT property> <!ATTLIST property xj:name CDATA #REQUIRED xj:value CDATA #REQUIRED >
An image node must have an "xj:op" attribute specifying the JAI operator name (as given in the Javadoc) followed by any parameters required by the operator, again using the parameter names given in the Javadoc for the operator. The XML operator knows how to convert simple values such as float, double, integer, boolean as well as some common types such as interpolation types to the appropriate type.
For tree-structured graphs, the image node is the only node needed. To create a DAG, you need to use the imageref node. This makes a reference to an image node created elsewhere in the file. The name is defined in the image node using the "xj:name" attribute.
Beware: this operator performs very little sanity checking on its input file. In particular it won't spot cycles in the operator graph or wrongly nested elements. The only indication you'll get of any error is an enormous stack trace, but as I said, this was a quick testing hack.