[ACCEPTED]-Resize image while keeping aspect ratio in Java-resize

Accepted answer
Score: 72

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

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

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

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

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

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

If you want to override the automatic 25 mode and force it to give you the best-looking 24 result and even apply a very mild anti-alias 23 filter to the result so it looks even better 22 (especially good for thumbnails), that call 21 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 20 API is broad and covers everything from 19 super-simple use cases to very specialized. You 18 can even pass in your own BufferedImageOps 17 to be applied to the image (and the library 16 automatically fixes the 6-year BufferedImageOp 15 JDK bug for you!)

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

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

Hope 1 that helps.

Score: 10

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

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

(width / height) = (new_width / new_height)

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

new_height * (width / height) = new_width

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

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

Score: 10

If width, height of source and target are 4 known, use following function to determine 3 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 2 to scale up/down the image using following 1 code

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

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

The article also provides alternative 1 code.

Score: 3

I use these two methods to scale images, where 3 max is the bigger dimension of your destination 2 image. For 100x100 image it will be 100, for 1 200x300 image it will be 300.

    public static BufferedImage scale(InputStream is, int max) {
    Image image = null;
    try {
        image = ImageIO.read(is);
    } catch (IOException e) {
        e.printStackTrace();
    }
    int width = image.getWidth(null);
    int height = image.getHeight(null);
    double dWidth = 0;
    double dHeight = 0;
    if (width == height) {
        dWidth = max;
        dHeight = max;
    } 
    else if (width > height) {
        dWidth = max;
        dHeight = ((double) height / (double) width) * max;
    }
    else {
        dHeight = max;
        dWidth = ((double) width / (double) height) * max;
    }
    image = image.getScaledInstance((int) dWidth, (int) dHeight, Image.SCALE_SMOOTH);
    BufferedImage bImage = toBufferedImage(image);
    return bImage;

}

public static BufferedImage toBufferedImage(Image img)
{
    if (img instanceof BufferedImage)
    {
        return (BufferedImage) img;
    }

    BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

    Graphics2D bGr = bimage.createGraphics();
    bGr.drawImage(img, 0, 0, null);
    bGr.dispose();

    return bimage;
}
Score: 0

If you want to resize a picture of w0 x 3 h0 to w1 x h1 by keeping the aspect ratio, then 2 calculate the vertical and horizontal scale 1 and select the smaller one.

double scalex = 1;
double scaley = 1;
if (scalingMode == ScalingMode.WINDOW_SIZE) {
  scalex = (double)getWidth() / frontbuffer.getWidth();
  scaley = (double)getHeight() / frontbuffer.getHeight();
} else
if (scalingMode == ScalingMode.KEEP_ASPECT) {
  double sx = (double)getWidth() / frontbuffer.getWidth();
  double sy = (double)getHeight() / frontbuffer.getHeight();
  scalex = Math.min(sx, sy);
  scaley = scalex;
  // center the image
  g2.translate((getWidth() - (frontbuffer.getWidth() * scalex)) / 2,
    (getHeight() - (frontbuffer.getHeight() * scaley)) / 2);
}
g2.scale(scalex, scaley);
if (interpolation != ImageInterpolation.NONE) {
  g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation.hint);
}
g2.drawImage(frontbuffer, 0, 0, null);
Score: 0
private static BufferedImage resize(BufferedImage img, int width, int height) {

        double scalex = (double) width / img.getWidth();
        double scaley = (double) height / img.getHeight();
        double scale = Math.min(scalex, scaley);

        int w = (int) (img.getWidth() * scale);
        int h = (int) (img.getHeight() * scale);

        Image tmp = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);

        BufferedImage resized = new BufferedImage(w, h, img.getType());
        Graphics2D g2d = resized.createGraphics();
        g2d.drawImage(tmp, 0, 0, null);
        g2d.dispose();

        return resized;
    }

0

More Related questions