Imaging: extracting pages from a TIFF
2009/04/20 Leave a comment
Today I found myself facing an apparently simple task, but we all know that when it comes with files formats, simple is just a hope, not a fact. TIFF format is a common way to store multi-page images. They’re very popular among scanners and faxes.
My task was to programmatically run a program over the first page to detect some data. Ah, did I mention the program only accepts JPEG images? Extracting the first page for the program processing seemed to be a logic solution.
How many times you used TIFFs in your Java programs? Never? There’s a reason. TIFF ain’t so popular after all and handling it with Java JRE base functions seems to be impossible.
The only reasonable solution appears to be Sun JAI (Java Advanced Imaging) that is a JVM extension you can download here:
http://java.sun.com/javase/technologies/desktop/media/
No, I know what you’re thinking, it’s a JVM extension you can’t simply include “a jar”. At the same URL you’ll find Image I/O library that might be necessary for what you’ll be doing with your TIFF, but it’s a jar and you can just add it to your classpath.
Let’s get down to it. The first thing we need to do is to create a SeekableStream that will allow us direct access to specific positions in a stream.
SeekableStream stream = new FileSeekableStream(new File(file));
Next we need a decoder that will let us read the data:
TIFFDecodeParam param = null; ImageDecoder dec = ImageCodec.createImageDecoder("tiff", stream, param);
Our image decoder can now hand us all the information we need, say, the number of pages?
int pages = dec.getNumPages();
Here we go, now let’s cycle on the pages and turn them into BufferedImage objects with which you can do whatever you want. I won’t go deep in the topic of writing images to files now, but I accept requests of course.
for(int i=0;i<pages;i++){ RenderedImage op = new NullOpImage(dec.decodeAsRenderedImage(i), null, OpImage.OP_IO_BOUND, null); BufferedImage bi = new BufferedImage(op.getWidth(), op.getHeight(), BufferedImage.TYPE_INT_RGB); //processing... doStuffToPage(bi); }
Keep in mind that you’ll need to distribute JAI too when you distribute your program!
Cheers