Resize image while keeping aspect ratio in Java

Adding to Erik's point about getScaledInstance, if you moved away from it to using the recommended scaling mechanisms in Java2D, you might have noticed that your images look noticeably worse.

The reason for that is when the Java2D discouraged use of getScaledInstance and AreaAveragingScaleFilter, they didn't replace it with anything as easy to use in the API, instead we were left to our own devices using Java2D APIs directly. Fortunately, Chris Campbell (from the J2D team) followed up with the recommendation of using an incremental scaling technique that gives similar looking results to AreaAveragingScaleFilter and runs faster; unfortunately the code is of a decent size and doesn't address your original question of honoring proportions.

About 6 months ago I saw all these questions on SO again and again about "scaling images in Java" and eventually collected all the advice, did all the digging and research I could, and compiled all of into a single "best practices" image scaling library.

The API is dead simple as it is only 1 class and a bunch of static methods. Basic use looks like this:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 320);

This is the simplest call where the library will make a best-guess at the quality, honor your image proportions, and fit the result within a 320x320 bounding box. NOTE, the bounding box is just the maximum W/H used, since your image proportions are honored, the resulting image would still honor that, say 320x200.

If you want to override the automatic mode and force it to give you the best-looking result and even apply a very mild anti-alias filter to the result so it looks even better (especially good for thumbnails), that call would look like:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

These are all just examples, the API is broad and covers everything from super-simple use cases to very specialized. You can even pass in your own BufferedImageOps to be applied to the image (and the library automatically fixes the 6-year BufferedImageOp JDK bug for you!)

There is a lot more to scaling images in Java successfully that the library does for you, for example always keeping the image in one of the best supported RGB or ARGB image types while operating on it. Under the covers the Java2D image processing pipeline falls back to an inferior software pipeline if the image type used for any image operations is poorly supported.

If all that sounded like a lot of headache, it sort of is... that's why I wrote the library and open sourced it, so folks could just resize their images and move on with their lives without needing to worry about it.

Hope that helps.


For starters - take a look at line 2. Shouldnt that be getHeight()?

You dont want a while loop for the resizing, you want to find out the resizing ratio, which is a simple bit of math.

(width / height) = (new_width / new_height)

If you know one of the 'new' sizes, the other can be found via multiplication

new_height * (width / height) = new_width

You can also use the lazy method provided by BufferedImage's superclass Image, getScaledInstance() - using -1 for either width or height will maintain aspect ratio

ex:
scaledPic = picture.getScaledInstance(new_width, -1, Image.SCALE_FAST);


You may have a look at perils-of-image-getscaledinstance.html that explains why getScaledInstance(), used in some of the answers, should be avoided.

The article also provides alternative code.


If width, height of source and target are known, use following function to determine scale of the image.

private double determineImageScale(int sourceWidth, int sourceHeight, int targetWidth, int targetHeight) {

double scalex = (double) targetWidth / sourceWidth;
double scaley = (double) targetHeight / sourceHeight;
return Math.min(scalex, scaley);

}

Then use this scale to scale up/down the image using following code

Image scaledImage = sourceBufferedImage.getScaledInstance((int) (width * scale), (int) (height * scale), Image.SCALE_SMOOTH);

Tags:

Java

Image

Resize