Java Advanced Imaging

The Java Advanced Imaging (JAI) API is a standard Java extension that allows reading and writing of various image formats, and manipulation (such as cropping, resizing and translating) of images.

An Example

Recently, we were trying to figure out a good way to resize images for the wiki engine that drives i-Proving.ca. One of the basic approaches is just to specify an image tag with a “resized” height and width.

Unfortunately, browsers do a terrible job of resizing images. Consider the following. We have an image from Wikipedia which is sized at 1880 pixels wide, and we want to show it at 250 pixels wide.

Simply using the browser to force a resize causes nasty “jagged” lines. This is called “aliasing” in image-speak. Here’s an example:

Notice how poorly the image resized.

We downloaded the JAI code from Sun’s site to build some server-side resizing of the images. Scouring the web, we found some code that resized our image:

// read in the original image from an input stream
SeekableStream s = SeekableStream.wrapInputStream(
  inputStream, true);
RenderedOp image = JAI.create("stream", s);
((OpImage)image.getRendering()).setTileCache(null);

// now resize the image

float scale = newWidth / image.getWidth();

ParameterBlock pb = new ParameterBlock();
pb.addSource(image); // The source image
pb.add(scale);          // The xScale
pb.add(scale);          // The yScale
pb.add(0.0F);           // The x translation
pb.add(0.0F);           // The y translation
pb.add(new InterpolationNearest()); // The interpolation

RenderedOp resizedImage = JAI.create("scale", pb, null);

// lastly, write the newly-resized image to an
// output stream, in a specific encoding

JAI.create("encode", resizedImage, outputStream, "PNG", null);

This example didn’t work terribly well for us, and we ended up getting a lot of aliasing.

We were initially concerned about the “interpolation”parameter in our resize operation. This is the mechanism that we use to figure out how to determine the newly-sized pixels.

In standard image-manipulation tools like Jasc’s PaintShop Pro, I usually use something called “Bicubic” resizing. Turns out that I can replace my interpolation method with this:

pb.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));

Even that yielded only mediocre results. So, scouring the web again, we found examples that encouraged us to try a “Subsample Average” operation instead of a “resize”:

RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_RENDERING,
    RenderingHints.VALUE_RENDER_QUALITY);

RenderedOp resizedImage = JAI.create("SubsampleAverage",
    image, scale, scale, qualityHints);

This yielded the best results:

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply