Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scaling images with Java JAI

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?

like image 764
Basil Avatar asked Nov 18 '10 23:11

Basil


People also ask

Can you resize images in Java?

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.

How do you proportionally scale an image?

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.

How do I change the scale of an image?

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.


3 Answers

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.

like image 139
Riyad Kalla Avatar answered Oct 30 '22 02:10

Riyad Kalla


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

like image 25
fj.aquino Avatar answered Oct 30 '22 02:10

fj.aquino


If you are lucky and you have only Black & White images, then you can use very fast and good quality operation: SubsampleBinaryToGray

like image 39
Dmitry Mitskevich Avatar answered Oct 30 '22 02:10

Dmitry Mitskevich