Skip to content

March 2, 2011

15

Resize images in Java, preserving image quality

It shouldn’t be so difficult to do simple image manipulation in java.  Resizing images is a frequently-encountered need, often to create thumbnails or to shrink pictures taken from digital cameras to a reasonable display size.  But how to create thumbnails in java without sacrificing image quality?  Standard library image manipulation is severely lacking in this area.

Luckily, talented java programmers have worked to create better solutions.  I’ve thrown together an image utility, building off of the work of others, to expose a few basic image manipulation functions, namely: open (from a file, URL, InputStream or byte array), save to file, soften, resize, and resize to square.  This may be useful to your project.  Just read the important caveat toward the bottom of this post.

I make no warrantees about this utility.  If you like it, a link back to this blog would be more than welcome.

I’ve done a lot of online research looking for a good image resizing solution in java, and I believe Morten Nobel-Jørgensen’s java image scaling library fits that description.  Specifically, I chose to use his MultiStepRescaleOp class, which does not have high memory usage.  More info here.  I also take advantage of an unsharp filter, which is part of this incredible java image filter set.

Loading images is easy with the ImageLoader class. Example:

// load an image from a URL
image = ImageLoader.fromUrl("http://example.com/file.gif");
// from a file
image = ImageLoader.fromFile("c:\pictures\mypic.jpg");
//from an InputStream
image = ImageLoader.fromStream(input);
//from a byte array
image = ImageLoader.fromBytes(imageBytes);

The zip file above contains an example usage class, which you can look at and run from the command line like so:

java -classpath ./dist/ImageUtil.jar;./lib/java-image-scaling-0.8.5.jar;./lib/Filters.jar imageUtil.Example http://upload.wikimedia.org/wikipedia/commons/7/74/06._John_in_the_vineyard.jpg

The wikimedia URL is just an image in their public domain category.  The imageUtil.Example class accepts local files as well as URLs as arguments.  After executing the above command, the following images are generated. A demonstration of cropping first.

Cropping With Java

java image cropped

image.crop(200, 200, 500, 350);

Resizing With Java, Varying Quality

Images resized and saved with increasing quality (most evident in the shoulder strap):

resized in java, low quality

image.getResizedToWidth(400).soften(0.08f).writeToJPG(new File("filename"), 0.4f);

resized in java, medium quality

image.getResizedToWidth(400).soften(0.08f).writeToJPG(new File("filename"), 0.6f);

resized in java, high quality

image.getResizedToWidth(400).soften(0.08f).writeToJPG(new File("filename"), 0.8f);

resized in java, very high quality

image.getResizedToWidth(400).soften(0.0f).writeToJPG(new File("filename"), 0.95f);

(Note that the file sizes range from 11,835 bytes to 55,654 bytes.)

Resizing With Java, Varying Softness

More examples, this time with increasing softness added.  The soften method adds a slight blur to improve the look of sharp edges following a resize operation.  (Please note, the image just above has zero softness applied.)

slightly softened in java

image.getResizedToWidth(400).soften(0.1f).writeToJPG(new File("filename"), 0.95f);

moderately softened in java

image.getResizedToWidth(400).soften(0.2f).writeToJPG(new File("filename"), 0.95f);

aggressively softened in  java

image.getResizedToWidth(400).soften(0.3f).writeToJPG(new File("filename"), 0.95f);

The amount of softness you’d like to apply is a judgement call.  I find 0.08f to be a good setting.

Squaring Images With Java

Next, the squaring method.  Note that the preceding images retained their original aspect ratio.  Often, you’d like thumbnails or picture icons to be square.  The method getResizedToSquare(int width, double cropEdgesPct) does this by cropping any excess width or height to form a square, then resizing to your desired size.  The second argument, called cropEdgesPct, specifies how much, if any, additional cropping to perform around the entire border of the square.  This results in a zoom effect.  It is useful because when you resize images down thumbnails, a lot of detail is lost.  If we assume that the main subject of the picture is relatively centered, a zoom effect will preserve as much main subject detail as possible.

Here are some examples, with increasing degrees of edge cropping:

cropped, resized in java

image.getResizedToSquare(400, 0.0).soften(0.08f).writeToJPG(new File("filename"), 0.95f);

resized, cropped in java

image.getResizedToSquare(400, 0.1).soften(0.08f).writeToJPG(new File("filename"), 0.95f);

cropped, resized in java

image.getResizedToSquare(400, 0.2).soften(0.08f).writeToJPG(new File("filename"), 0.95f);

Next, let’s look at some little square thumbnails.  Resizing images down to such a small size tends to be problematic in terms of image detail.  Here are a few examples created with various settings.

thumbnail created in java

square, 0.0 crop, 0.95 quality

thumbnail created in java

square, 0.1 crop, 0.95 quality

thumbnail created in java

square, 0.1 crop, 0.5 quality

Note that applying a little edge cropping brings greater focus to the face, which in this case is within the center area of the squared image.  Also note the degradation when specifying a lower quality.  Be aware that higher quality images require greater disk space.  The center image has twice the file size as the right-most image.

* Important caveat with this utility: the writeToJPG method uses Sun’s JPEGCodec class, which is available in Sun JVMs only.  The reason for using this class is that it is able to produce higher-quality JPG files than the alternative,  the ImageIO.write method.  The latter does not allow you to set the desired image quality.  Here is a comparison of two resized images, one using JPEGCodec and the other using ImageIO to write the file:

resized in java with JPEGCodec

JPEGCodec at 0.95 quality, no softening

resized in java, ImageIO

ImageIO.write, no softening

The output from JPEGCodec is better. Again, compare the shoulder straps.  The downside is that using the JPEGCodec class is not portable across different JREs.

If this was at all helpful, I would greatly appreciate a link!  If you have a blog on programming or web development, let’s trade links.

Read more from Java
15 Comments Post a comment
  1. Mar 11 2011

    Thanks a ton for this! I have your little library up and running like a charm. I’m using it for a live stop-motion animation performance to resize images from my camera on the fly and project them in a sequence.

    On a side note, a friend of mine just started a company called TipTheWeb that provides a mechanism for making small donations for web content. It’s in Beta now. For fun I just tried to use it to send you $10 as a show of gratitude. I’d be curious to know what kind of notification you get and/or how it reaches you.

    Cheers, and thanks again.
    -mike

    Reply
  2. Graeme
    Mar 19 2011

    Wow! after lots of searching I found this and got it working within 5 minutes! GREAT WORK!!

    Reply
  3. mily
    May 20 2011

    thanks a lot

    Reply
  4. ryan
    May 26 2011

    wow. you are genius~!!.

    Reply
  5. Luis Rico
    Aug 12 2011

    Very Nice! Congrats
    Now you should think about creating a maven project on it and add it to a public repository! 😉

    cheers

    Reply
  6. John
    Aug 21 2011

    Very effective and easy to implement

    Reply
  7. Andrei
    Jan 14 2012

    Thanks for the nice package. The only problem I have is with PNG images with transparency. If I use writeToJPG it produces black boxes. It is well known problem. I solved it with substitution of transparent pixels with white colour.

    Here is the working solution:

    http://stackoverflow.com/questions/464825/converting-transparent-gif-png-to-jpeg-using-java

    Reply
  8. Wim
    Feb 5 2012

    Thank you! Your image library was the only one that worked to satisfaction. However, I understand that it will only work with the Sun (RIP) SDK. I can live with that.

    Thank you for sharing.

    Wim.

    Reply
  9. Mar 7 2012

    thanks a lot!

    I add this function to you Image.java.

    /**
    *
    * @param stream
    * @param type
    * @throws IOException
    */
    public void writeToStream(OutputStream stream, String type) throws IOException {
    if (stream == null) {
    throw new IllegalArgumentException(“stream argument was null”);
    }
    ImageIO.write(img, type, stream);
    }

    Reply
  10. Fábio
    Dec 18 2012

    Nice, I’m using it and it’s working fine.
    After long and unsuccessful search for a program that make batch resize of images (the way I want), I decided to search for some Java code and I found this. Thanks.
    *I’m thinking about to distribute the little app I’m doing…

    Reply
  11. Eddie
    Dec 30 2012

    Works great! And fast too- thank you!!

    Reply
  12. Nghia
    Jul 29 2013

    Dear,
    Your lib is definately aswesome. However, please show me how could I rescale the image on the UI (such like facebook).
    Thank you so much.

    Reply
  13. godswill
    Aug 6 2013

    can i alter image dpi with this tool?

    Reply
  14. rokta
    Nov 1 2013

    Thanx , very nice Work

    Reply
  15. Ali Reza Akbariyan
    Nov 10 2013

    good library, thank you.

    Reply

Share your thoughts, post a comment.

(required)
(required)

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments