Create High Quality Thumbnails using the imgscalr Library

By Rob Gravelle

Create High Quality Thumbnails using the imgscalr Library

Just about any Web or mobile app that works with images needs to display thumbnails. In fact, we saw such an app in the Display a Thumbnail using the Vaadin Application FileUpload Control tutorial. That app employed the Image.getScaledInstance() method using the SCALE_SMOOTH algorithm. The Java 2D team has been encouraging developers to move away from Image.getScaledInstance() to more modern APIs due to its poor performance. Native Java offers many alternatives, but sadly, none of them can generate as high quality thumbnails as the Image.getScaledInstance() + SCALE_AREA_AVERAGING combo. Therefore, if you need to quickly resize or manipulate images using the most optimal methods, then you should strongly consider using a specialized library like imgscalr. As the name implies, it was created for one purpose and one purpose only: to resize images quickly, easily, and well. In today's article, we'll learn how to use imgscalr to resize, crop, pad, and even rotate images.

Download and Installation

Imgscalr may be downloaded from their website under Download section. It is available at no cost under the Apache 2 License. All Download bundles include the library JAR, source code and Javadocs.

The only jar that your project needs to reference is the imgscalr-lib-x.x.jar where x.x is the exact version number. At the time of this writing, version 4.2 is most current.

Resing Images

Image resizing is achieved via several overloaded versions of the static Scalr.resize() method. The simplest accepts two arguments: the BufferedImage and targetSize int. That will resize a given image while maintaining its original proportion to a width and height no bigger than the targetSize:

File image = new File("C:\\Users\\Public\\Pictures\\Sample Pictures\\mypicture.jpg");
BufferedImage img = ImageIO.read(image); // load image
//resize to 150 pixels max
BufferedImage thumbnail = Scalr.resize(image, 150);

For more fine-grained control over how our image is scaled, other attributes such as quality and filtering can be set via additional parameters:

BufferedImage thumbnail = Scalr.resize(image,
                                       Scalr.Method.SPEED,
                                       Scalr.Mode.FIT_TO_WIDTH,
                                       150,
                                       100,
                                       Scalr.OP_ANTIALIAS);

Here is what each of the above parameters specifies:

  • src - The BufferedImage that will be scaled.
  • scalingMethod - A Scalr.Method enum that favors speed to quality or a balance of both.
  • resizeMode - A Scalr.Mode enum indicating how imgscalr should calculate the final target size for the image, either fitting the image to the given width (Scalr.Mode.FIT_TO_WIDTH) or fitting the image to the given height (Scalr.Mode.FIT_TO_HEIGHT). If Scalr.Mode.AUTOMATIC is passed in, imgscalr will calculate proportional dimensions for the scaled image based on its orientation (landscape, square or portrait). Unless you have very specific size requirements, most of the time you just want to use Scalr.Mode.AUTOMATIC to "do the right thing".
  • targetWidth - The target width (int) that you wish the image to have.
  • targetHeight - The target height (int) that you wish the image to have.
  • ops - Zero or more optional image operations (e.g. sharpen, blur, etc.) of type BufferedImageOp that can be applied to the resized image. These include OP_BRIGHTER, OP_ANTIALIAS and OP_BRIGHTER, OP_ANTIALIAS.

By default imgscalr always honors the image's original proportions above all else. If either of the target dimensions are wrong, imgscalr will re-calculate proper dimensions honoring the primary dimension of the image first, based on the image's orientation. To force imgscalr to resize an image into new dimensions, use the FIT_EXACT Scalr Mode.

Reducing Source Code

Since all of imgscalr's method's are static, you can add a static import for the entire library to remove all of the Scalr." object prefixes in your code. Here is the previous example rewritten with a static import:

import static org.imgscalr.Scalr.*;
 
BufferedImage thumbnail = resize(image,
                                 Method.SPEED,
                                 Mode.FIT_TO_WIDTH,
                                 150,
                                 100,
                                 OP_ANTIALIAS);

Other Useful Methods

Imgscalr can also be utilized to pad, crop, and rotate images.

For instance, the following code invokes the pad() method to add a black border of 2 pixels around a resized image:

import org.imgscalr.Scalr.*;
import java.awt.Color;
public static BufferedImage createThumbnail(BufferedImage img) {
    // Target width of 500x500 is used
    img = resize(img, 500);
    return pad(img, 2, Color.BLACK);
}

This class is a simplified version of the one found on the Java Free Learning Blog. It resizes an image and then applies cropping and padding to it:

import javax.imageio.ImageIO;

import org.imgscalr.Scalr;
import org.imgscalr.Scalr.Method;
import org.imgscalr.Scalr.Mode;

public class ImageResize {
  public static void main(String[] args) throws IOException {
    BufferedImage image = ImageIO.read(new File("shutterstock_24045112.jpg"));
    BufferedImage small = Scalr.resize(image,
                                       Method.ULTRA_QUALITY,
                                       Mode.AUTOMATIC,
                                       500, 500,
                                       Scalr.OP_ANTIALIAS);

    BufferedImage cropimage = Scalr.crop(image, 1000, 1000, Scalr.OP_ANTIALIAS);
    BufferedImage padding   = Scalr.pad(image, 200, Scalr.OP_DARKER);
    ImageIO.write(padding, "jpg", new File("shutterstock_24045112_thumb.jpg"));
  }
}

Finally, this example rotates an image by 90 degrees:

File file= new File("animage.png");
BufferedImage src = ImageIO.read(file);
BufferedImage rotated = Scalr.rotate(src, Scalr.Rotation.CW_90, Scalr.OP_ANTIALIAS);
BufferedImage scaled  = Scalr.resize(rotated, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_HEIGHT, 1336, 768, Scalr.OP_ANTIALIAS);
ImageIO.write(scaled,"png" , "/rotated.png");

Don't Forget the Error Handling

Be prepared for possible exceptions whenever you invoke imgscalr methods. In particular, java.lang.IllegalArgumentExceptions and java.awt.image.ImagingOpExceptions are common because they bubble up from the underlying Java BufferedImage class.

try {
  BufferedImage thumbnail = Scalr.resize(sourceFile,       
                                         Scalr.Method.ULTRA_QUALITY,
                                         Scalr.Mode.AUTOMATIC,
                                         destinationSize.width,
                                         destinationSize.height);
  if (thumbnail.getWidth() > destinationSize.width) {
    thumbnail = Scalr.crop(thumbnail,
                           (thumbnail.getWidth() - destinationSize.width) / 2,
                           0,
                           destinationSize.width,
                           destinationSize.height);
  }
  else if (thumbnail.getHeight() > destinationSize.height) {
    thumbnail = Scalr.crop(thumbnail,
                           0,
                           (thumbnail.getHeight() - destinationSize.height) / 2,
                           destinationSize.width,
                           destinationSize.height);
  }
}
catch(IllegalArgumentException | ImagingOpException e) {
  System.out.println("imgscalr threw an exception: " + e.getMessage());
}

Conclusion

I consciously chose to omit before and after images. Instead, I would urge you to try the above code examples on your own files and see the resulting output for yourself. I think that you'll be pleasantly surprised with the results!


Rob Gravelle

Rob Gravelle resides in Ottawa, Canada, and is the founder of Gravelle Web Design. Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS as well as for numerous commercial businesses.

In his spare time, Rob has become an accomplished guitar player, and has released several CDs. His band, Ivory Knight, was rated as one Canada's top hard rock and metal groups by Brave Words magazine (issue #92) and reached the #1 spot in the National Heavy Metal charts on reverbnation.com.



Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •  
  •  
  •  
Thanks for your registration, follow us on our social networks to keep up-to-date