Monday, June 07, 2004

This week I've been learning a great deal about the image handling that is built in the JDK 1.4. Specifically, the javax.imageio.* packages. I've been mainly interested in two things: validating that a file is an image and gathering its meta data, and resizing the image. If users upload an image that is larger than we want to allow, I want to be able to reduce the image to an allowed size so they have the choice of using the smaller image. That way the upload wasn't a complete waste of time.

I accomplished the first step with code like this:


ImageInfo info = new ImageInfo();

try
{
Iterator imageReaders = ImageIO.getImageReaders(ImageIO.createImageInputStream(formFile.getInputStream()));

while (imageReaders.hasNext())
{
ImageReader reader = (ImageReader) imageReaders.next();

info.type = ImageType.getImageType(reader.getFormatName());

if( info.type != null )
{
break;
}
}

if( info.type == null )
{
return null;
}


try
{
BufferedImage theImage = ImageIO
.read(formFile.getInputStream());

info.height = theImage.getHeight();
info.width = theImage.getWidth();
info.fileSize = formFile.getFileSize();

theImage = null;
}
catch (Exception e)
{
log.debug("Exception caught trying to read image", e);
return null;
}

log.debug("Parsed image info: " + info);


I could probably have been more efficient and used the ImageReader I found in the first part of the code to actually read in the image instead of relying on ImageIO.read(). I've only today just been able to figure out that that's an option. The ImageIO guide claims the API was developed with application developer ease-of-use as a top priority. I'm sure it was, but I still think people like myself would benefit from some clear recipes for common operations. Almost everyone posting forum questions about image resizing is doing so for the same reasons as me, so it's clearly a confusing issue. It doesn't help that there's another API, the Java Advanced Imaging API, to confuse the issue. And there appear to be multiple ways to accomplish the goal of resizing an image making the whole thing rather confusing. </rant>

Resizing the image was a bit more difficult with the issue complicated by a bug in the 1.4.1 JDK. Upgrading to 1.4.2_4 fixes the issue (handling of certain JPEGs), but it still took me a while to figure out. Here's how I resize:


File inFile = new File(...);

InputStream is = new FileInputStream( inFile );

BufferedImage bufIn = ImageIO.read(is);

is.close();

// scale is a float with 1 being no change in size, 2 doubling, 0.5 halving...
AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(scale, scale), null);

bufIn = op.filter( bufIn, null );

File outFile = new File(...);

ImageIO.write(bufIn, imageInfo.type.getFormatName(), outFile);




Unfortunately, I'm still not accomplishing my goal with 100% success. I can reduce the file size of an image by scaling it by 50%, but on my test file, 90% scaling actually makes the file considerably larger. And there's really no way to specify a scaling based on file size that I've found. Perhaps I'll have to break down and post questions to the java.sun.com forums...


No comments: