I have to scale an image with Java JAI. At the time now, I use the following code:
private static RenderedOp scale(RenderedOp image, float scale) {
ParameterBlock scaleParams = new ParameterBlock();
scaleParams.addSource(image);
scaleParams.add(scale).add(scale).add(0.0f).add(0.0f);
scaleParams.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2));
// Quality related hints when scaling the image
RenderingHints scalingHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
scalingHints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
scalingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
scalingHints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
scalingHints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
scalingHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
scalingHints.put(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));
return JAI.create("scale", scaleParams, scalingHints);
}
Unfortunately, this leads to very bad results, especially because I often have to scale images with a scale factor less than 0.5...
Any advice?
You can resize an image in Java using the getScaledInstance() function, available in the Java Image class. We'll use the BufferedImage class that extends the basic Image class. It stores images as an array of pixels.
If the Shift key is held down whilst moving the handle, then the proportions of the object will be preserved. For example, if I hold Shift and drag the bottom edge upwards to reduce the size by half, then the right edge will automatically move to the left to reduce the width of the object by the same amount.
Step 1: Right-click on the image and select Open. If Preview is not your default image viewer, select Open With followed by Preview instead. Step 2: Select Tools on the menu bar. Step 3: Select Adjust Size on the drop-down menu.
I am guessing you are trying to scale a larger image down to a thumbnail size or some equally large difference from original to scaled image?
If-so, this topic was actually address by Chris Campbell from the Java2D back in 2007 (I am not expecting you knew this, just pointing out that it's a common question) because the new Java2D scaling approaches (RenderingHints.VALUE_INTERPOLATION_*) did not provide an equivalent to the then-deprecated Image.getScaledInstance(SCALE_AREA_AVERAGING or SCALE_SMOOTH) approach.
As it turns out, the SCALE_AREA_AVERAGING or SCALE_SMOOTH approaches in the old Java 1.1 Image.getScaledInstance approach was a fairly expensive, multi-step operation that was doing a lot of work in the background to generate that nice-looking image.
Chris pointed out that the new and "correct" way, using Java2D, to get this same result is an incremental process of scaling the image in-half over and over until the desired image size is reached, preferably using a higher-quality scale like RenderHints.VALUE_INTERPOLATION_BICUBIC or BILINEAR.
The result comes out almost identical to the original Image.getScaledInstance approach that folks want.
I actually went hunting for this answer a few months ago while writing an image-hosting service and was surprised at how complicated the simple question of "How do I make a nice looking thumbnail in Java?" became.
I eventually create a small Java library (Apache 2, open sourced) that implements 3 different approaches to image scaling in Java using "best practices" including the incremental approach that Chris suggested.
The library is called imgscalr. You can download and use it as simple as:
BufferedImage thumbnail = Scalr.resize(srcImage, 150);
There are more options to set and use (e.g. the Quality or Speed of the scaling) but out of the box there are intelligent defaults for everything to make a nice looking scaled image for you so you don't have to worry about more if you don't want to. The library also makes a strong effort to dispose of and avoid any Object allocation that isn't absolutely necessary and dispose of BufferedImage instances immediately if not needed -- it is intended to be code as part of a long-running server app so this was critical.
I've made a few releases of the library already, and if you'd rather just rip out the "good stuff" and do something with it yourself, go for it. It is all on GitHub and none of it is top secret, just an attempt to make people's lives easier.
Hope that helps.
I've obtained good results with Thumbnailator. I don't know what JAI.KEY_BORDER_EXTENDER is supposed to do, but I guess the rest of the functionality (antialiasing, dithering, etc) is supported. I used it to generate grayscale thumbnails of quite big black and white images
If you are lucky and you have only Black & White images, then you can use very fast and good quality operation: SubsampleBinaryToGray
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With