Mini Builds

Using ImageIO to Generate Thumbnails in Java

March 20, 2021

In this article we will take an image and create a thumbnail image from it in Java. The thumbnail will be of a set size and aspect ratio, if the aspect ratio of the original and thumbnail don’t match the original will be cropped as demonstrated above.

This example uses the javax.imageio package hence should just run out of the box with Java SE.

Checkout on GitHub

You can find a full application in the GitHub repo: https://github.com/mini-builds/thumbnail-imagio

Example

// read image to generate a thumbnail from
BufferedImage originalImage = ImageIO.read(imageFile);

// create a blank image which we use as a canvas to draw the thumbnail
BufferedImage thumbImage = new BufferedImage((int) thumbnailSize.getWidth(),
        (int) thumbnailSize.getHeight(), BufferedImage.TYPE_INT_RGB);

// create a transform to scale and translate the original image
AffineTransform transform = calculateThumbnailTransform(originalSize,
        thumbnailSize);

// draws the image on to the canvas with the transform applied
thumbImage.createGraphics().drawImage(originalImage, transform, null);

The code below creates a transform such that the original image covers the entire thumbnail image, is centred, and doesn’t change the aspect ratio of the original.

Other behaviour such as simply forcing the image down to the thumbnail size ignore distortion can be achieved by changing this method.

public static AffineTransform calculateThumbnailTransform(
    Dimension originalSize, Dimension thumbnailSize) {

    AffineTransform transform = new AffineTransform();

    // scale down to fit as much of the image in as possible
    double scale = Math.max(
        thumbnailSize.getWidth() / originalSize.getWidth(), 
        thumbnailSize.getHeight() / originalSize.getHeight());

    // translate either to the left or up if the image was too width or tall
    transform.translate(
        -0.5 * (scale * originalSize.getWidth() - thumbnailSize.getWidth()), 
        -0.5 * (scale * originalSize.getHeight() - thumbnailSize.getHeight()));

    transform.scale(s, s);
    return transform;
}

Pushing to S3 or Similar Storage

Typically, you’ll upload the generated thumbnail to an S3 bucket which can be achieved in memory by writing the image to a ByteArrayOutputStream and piping it into a ByteArrayInputStream. Thus avoiding touching the filesystem.

ByteArrayOutputStream thumbOutputStream = new ByteArrayOutputStream();

ImageIO.write(thumbImage, formatName, thumbOutputStream);

InputStream inputStream = new ByteArrayInputStream(thumbOutputStream.toByteArray());

// upload inputStream...