I share this code which can be used to stitch image tiles together. I do this because I found that producing this code was quite a painful process. I am sure that there are other Java developers out there with similar requirements who, like me (an occasional Paint Shop Pro user), do not want to learn all the intricacies of image processing but want something quick and easy.
Every so often I need to stitch several images together. I am not a graphics designer so I do not have access to Adobe Photoshop and even if I did I would not know how to get it to amalgamate images. So invariably whenever I need to produce a montage of images I end up trawling the web for some freeware package, preferably something I can run from the command line and almost always I end up at ImageMagick. ImageMagick is good because I can run it from the command line and therefore script it. However, if you have other procedures that precede and follow the image processing stage then making a call out to a command line tool can seem a little too much like hard work.
With Java you can pretty much turn you hand to anything so why not this?Prior to image processing I had written the code to obtain the images I need from the net (using HttpClient). So I have my graphics files and a list of their file names.
The Java Advanced Imaging API (JAI) is supposed to make image processing easy. JAI does make life easier but IMHO it is quite poorly documented for beginners like me to use and there are not enough easy examples to copy.
My situation is that I have N PNG graphic images, arranged in an X x Y grid that I want to combine into a single image. The tiles are all the same size but (I don't know the technical term for this) have optimised palettes. By optimised palette, I mean to say that the palette of colours in the image only contains colours that are used in that image. From an efficiency standpoint, optimised palettes make sense (less colours, smaller files) but this is not particularly helpful when you need to combine several images all with different colour palettes.
So I wrote a program that positions each tile (what JAI calls a translate), converts the image palette into 24 bit true colour bitmap (at least I think that is what it does!) and finally combines all the images into a single image. Sounds easy but it took me quite a while to locate all the right code!
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.media.jai.LookupTableJAI;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.FileLoadDescriptor;
import javax.media.jai.operator.LookupDescriptor;
import javax.media.jai.operator.MosaicDescriptor;
import javax.media.jai.operator.TranslateDescriptor;
public class ImageMontageMaker {
public static void main(String[] args) throws FileNotFoundException, IOException {
int columnTotal = 1, rowTotal = 3;
int index = 0, col = 0, row = 0, height = 0, width = 0;
String[] files = {"x1y1.png","x1y2.png","x1y3.png"};
Vector renderedOps = new Vector();
RenderedOp op;
while(col<columnTotal){
row=0;
while(row<rowTotal){
System.out.println(index + ":" + files[index]);
System.out.println("c:" + col + "r:" + row);
// Load image
op = FileLoadDescriptor.create(files[index], null,null,null);
if (index == 0){
width = op.getWidth();
height = op.getHeight();
} else {
// TRANSLATE
// Translate source images to correct places in the mosaic.
op = TranslateDescriptor.create(op,(float)(width * col),(float)(height * row),null,null);
}
renderedOps.add(convert(op));
row++;
index++;
}
col++;
}
RenderedOp finalImage = MosaicDescriptor.create(
(RenderedImage[]) renderedOps.toArray(new RenderedOp[renderedOps.size()]),
MosaicDescriptor.MOSAIC_TYPE_OVERLAY,null,null,null,null,null
);
ImageIO.write(finalImage, "png", new File("out.png"));
}
public static RenderedOp convert(RenderedOp image){
// If the source image is colormapped, convert it to 3-band RGB.
if(image.getColorModel() instanceof IndexColorModel) {
// Retrieve the IndexColorModel
IndexColorModel icm = (IndexColorModel)image.getColorModel();
// Cache the number of elements in each band of the colormap.
int mapSize = icm.getMapSize();
// Allocate an array for the lookup table data.
byte[][] lutData = new byte[3][mapSize];
// Load the lookup table data from the IndexColorModel.
icm.getReds(lutData[0]);
icm.getGreens(lutData[1]);
icm.getBlues(lutData[2]);
// Create the lookup table object.
LookupTableJAI lut = new LookupTableJAI(lutData);
// Replace the original image with the 3-band RGB image.
image = LookupDescriptor.create(image,lut,null);
}
return image;
}
}
If you recognise any of this code then the chances are it probably is your code, I cobbled it together from several (open) sources!