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.
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:
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: