MEDIA GUIDES / Bulk Image Resize

3 Ways to Resize Images in Java

image resize java

Key takeaways

  • Resizing an image in Java doesn’t require any extra dependencies. The JDK gives you two routes: Graphics2D.drawImage() and Image.getScaledInstance().
  • Graphics2D is the faster of the two and gives the finer control over resampling, through RenderingHints. getScaledInstance() is a single call. Pass a negative value for one dimension and the JDK computes the other to keep the proportions.
  • Three libraries wrap this work: Thumbnailator, imgscalr and Marvin. A media platform such as Cloudinary moves the resize onto a delivery URL instead.

In this article:

  1. How Do You Resize Images in Java?
  2. Resizing an Image Using BufferedImage.getScaledInstance()
  3. Resizing an Image Using Graphics2D
  4. Automatically Resize and Crop Images in Java with Cloudinary

How Do You Resize Images in Java?

Let’s break down the individual steps on how to resize an image in Java:

  • Read the file into a BufferedImage with ImageIO.read().
  • Create a second BufferedImage at the desired dimensions.
  • Draw the first onto the second with Graphics2D.drawImage(), then write the result out with ImageIO.write().

The shorter alternative is one call to Image.getScaledInstance(), which costs you control over the resampling algorithm and runs several times slower.

Before the three techniques in detail, here is the whole operation end to end, so you have something that compiles before you read any further:

import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class QuickResize {

    public static void main(String[] args) throws IOException {
        BufferedImage original = ImageIO.read(new File("input.png"));
        if (original == null) {
            throw new IOException("No ImageIO reader could decode input.png");
        }

        BufferedImage resized = new BufferedImage(800, 500, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = resized.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g2d.drawImage(original, 0, 0, 800, 500, null);
        g2d.dispose();

        if (!ImageIO.write(resized, "png", new File("output.png"))) {
            throw new IOException("No ImageIO writer available for png");
        }
    }
}

That class writes output.png next to wherever you run it.

Techniques to Resize Images in Java

Resizing an Image Using BufferedImage.getScaledInstance()

You can resize an image in Java using the getScaledInstance() function, available in the Java Image class. We’ll use the BufferedImage class that extends the basic Image class. It stores images as an array of pixels.

First, we import the necessary Java libraries:

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

To read an image from the file system, we create an object from the BufferedImage class and use the ImageIO.read() method. The File() method calls the constructor of the File class, taking the path of the image as an argument.

BufferedImage bufferedImage = ImageIO.read(new File("C:\example.png"));

We now have a new object containing the image, which provides the getScaledInstance() method, which we can use to get a resized version of the image. The method takes the following arguments:

  • Target width in pixels after resizing
  • Target height in pixels after resizing
  • Image scaling algorithm (if you don’t have a special preference, you can use Image.SCALE_DEFAULT which uses the default sampling algorithm)

Here is how to scale the source image to 800 x 500 pixels:

Image image = bufferedImage.getScaledInstance(800, 500, Image.SCALE_DEFAULT);

Note that this operation scales the bufferedImage object in memory, but does not save the resized image to the file system, and also does not display the image.

Let’s display the resized image using a JFrame. We’ll set the layout to FlowLayout, which arranges components in the JFrame from left to right. We will also set the size of the JFrame to be larger than the image, ensuring that it is displayed in its entirety.

ImageIcon icon = new ImageIcon(image);
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
frame.setSize(1200, 800);

The last step is to display the image to the user. We’ll do this using a JLabel object, adding the JLabel to the frame and setting visibility to true.

JLabel jLabel = new JLabel();
jLabel.setIcon(icon);
frame.add(jLabel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Automatically resize and crop image with AI

Which Scaling Constant to Pass

The third argument selects the resampling algorithm, and it is the biggest single quality difference between two otherwise identical calls:

Constant Definition
SCALE_SMOOTH Prioritizes image smoothness over scaling speed.
SCALE_FAST Prioritizes scaling speed over image smoothness.
SCALE_DEFAULT Default image-scaling algorithm.
SCALE_AREA_AVERAGING Uses the Area Averaging image scaling algorithm.
SCALE_REPLICATE Uses the ReplicateScaleFilter class image scaling algorithm.

Use Image.SCALE_SMOOTH when a person is going to look at the output, which is also the first of the expert tips at the end of this guide. Keep SCALE_DEFAULT or SCALE_FAST for throughput work.

Resizing an Image Using Graphics2D

Another option for resizing an image in Java is the Graphics2D class. This class extends the Graphics class and provides fine-grained control over geometry, coordinate transformations, and color management for 2-dimensional shapes and images.

Here are the required imports:

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

Like in the previous example, we use ImageIO.read() and the File() method to read the image from the file system and store it as a BufferedImage object:

BufferedImage bufferedImage = ImageIO.read(new File("C:\example.png"));

We create another object that will store the resize operation result:

BufferedImage bufferedImageResult = new BufferedImage(
        resizeWidth,
        resizeHeight,
        bufferedImage.getType()
);

Passing bufferedImage.getType() into the constructor, as the snippet above does, may throw some errors with this approach. getType() returns TYPE_CUSTOM whenever the source color model is not one of the thirteen predefined types, and TYPE_CUSTOM is only used as a return value for the getType() method. Decide the destination type from the source alpha channel instead:

boolean keepAlpha = bufferedImage.getColorModel().hasAlpha();

BufferedImage bufferedImageResult = new BufferedImage(
    resizeWidth,
    resizeHeight,
    keepAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB
);

Now it’s time to use the g2d class. We’ll call the createGraphics() method, passing the bufferedImageResult object. This returns a g2d (Graphics2D) object.

Graphics2D g2d = bufferedImageResult.createGraphics();

Set the Rendering Hints Before You Draw

drawImage() resamples the source pixels, and the hints you set on the Graphics2D object beforehand decide how. Set none and you get the platform default, which sits at the fast end of the trade-off. Three hints matter for resizing:

Hint Value to use Effect
KEY_INTERPOLATION VALUE_INTERPOLATION_BICUBIC Samples a wider neighborhood of pixels than bilinear, which keeps edges cleaner when you shrink an image a long way. Use VALUE_INTERPOLATION_BILINEAR when throughput matters more.
KEY_RENDERING VALUE_RENDER_QUALITY Tells the pipeline to prefer quality over speed wherever it has a choice.
KEY_ANTIALIASING VALUE_ANTIALIAS_ON Smooths the diagonals and curves that go jagged after a downscale.
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
        RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
        RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);

These lines go after createGraphics() and before drawImage(). Setting them afterwards has no effect on a draw that has already happened.

We can now use the drawImage() function on the g2d object, which takes the following arguments:

  • A BufferedImage object
  • X and Y coordinates. For a resize operation, these should be set to 0.
  • The new height and width after resizing.
  • ImageObserver – handles notifications of image loading; not needed in this case and can be left as null.

The code looks like this:

g2d.drawImage(
        bufferedImage, 
        0, 
        0, 
        resizeWidth, 
        resizeHeight, 
        null
);

We use the following command to dispose of context and resources used by g2d, which are not necessary for the next steps:

g2d.dispose();

Finally, we save the resized image in the local directory using the ImageIO.write() function.

String formatName = imagePathToWrite.substring(
        imagePathToWrite.lastIndexOf(".") + 1
);
ImageIO.write(
        bufferedImageResult, 
        formatName, 
        new File(imagePathToWrite)
);

Automatically Resize and Crop Images in Java with Cloudinary

Cloudinary, a cloud-based service for managing images and videos, offers a generous free-forever subscription plan. On this platform, you can upload your images, apply built-in effects, filters, and modifications. You can also automatically resize images, focus on the most important elements using AI, or adapt them to your website design without the need to manually crop or scale them.

You can set the target dimensions of your resized image by specifying width, height, and/or the target aspect ratio as qualifiers of your resize transformation.

You can change the dimensions of an uploaded image by setting the image’s height, width, and/or aspect ratio, and Cloudinary automatically resizes or crops the image to fit into the requested size.

For example, this original image is 1200 x 1200 pixels:

three ways to resize

Resizing the image to 200 x 200 pixels, using crop, scale, fill and pad results in the following images:

3 ways to resize 200px

Adding the Cloudinary Java SDK

Configure the client from the environment, so no credentials sit in source control, then upload the original once:

<dependency>
    <groupId>com.cloudinary</groupId>
    <artifactId>cloudinary-http5</artifactId>
    <version>2.3.0</version>
</dependency>
import com.cloudinary.Cloudinary;
import com.cloudinary.Transformation;
import com.cloudinary.utils.ObjectUtils;
import java.util.Map;

// Reads cloud name, API key and API secret from the CLOUDINARY_URL
// environment variable.
Cloudinary cloudinary = new Cloudinary(System.getenv("CLOUDINARY_URL"));

Map<?, ?> uploaded = cloudinary.uploader().upload(
        "input.png",
        ObjectUtils.asMap("public_id", "products/chair"));

Resize Modes and Crop Modes Are Not the Same Thing

Every size you need after that is a transformation on the delivery URL, and the mode decides whether anything is removed. The Cloudinary resizing and cropping documentation splits the modes into two groups: scale, fit, limit, mfit, pad, lpad and mpad keep the whole image, while fill, lfill, fill_pad, crop, thumb and auto may remove part of it. Gravity decides what survives, so it applies to that second group only:

// Fit inside a 200 x 200 box, whole image kept, proportions kept
cloudinary.url().transformation(
        new Transformation().width(200).height(200).crop("fit"))
    .generate("products/chair");

// Fill a 200 x 200 square, cropping around the detected area of interest
cloudinary.url().transformation(
        new Transformation().width(200).height(200).gravity("auto").crop("fill"))
    .generate("products/chair");

// Square thumbnail centered on a detected face
cloudinary.url().transformation(
        new Transformation().width(200).height(200).gravity("faces").crop("thumb"))
    .generate("products/chair");

Chaining .chain().quality("auto").fetchFormat("auto") onto any of those then picks the compression level and the delivery format per browser, which is the part Graphics2D cannot do at all: your JVM doesn’t know what the requesting client supports.

Delivery and Security

Because the transformation lives in the URL, anyone who sees one can request other sizes unless you stop them. Cloudinary offers three options:

  • Strict transformations block transformations on the fly unless they are explicitly allowed.
  • Signed delivery URLs authorize dynamic transformations while strict transformations stay switched on.
  • Token-based access appends a signed token that restricts a URL by time, by IP address or by a path access control list, and its expiration parameter takes a UNIX timestamp in seconds so the URL stops working on a schedule.

What it doesn’t do is resize anything on your machine: the Transformation class builds a URL string, so the file has to reach Cloudinary first. That rules it out for offline and air-gapped work, and for images that are not allowed to leave your own infrastructure.

How Do You Resize an Image in Java Without Distorting It?

Passing a fixed width and height stretches the image whenever the target proportions are different from the original. Instead, find both numbers from one scale factor and take the smaller of the two ratios so the whole image lands inside the box you have:

static int[] fitInside(BufferedImage original, int boxWidth, int boxHeight) {
    double scale = Math.min(
            (double) boxWidth / original.getWidth(),
            (double) boxHeight / original.getHeight());

    // Drop this line if you also want small images enlarged to fill the box.
    scale = Math.min(scale, 1.0);

    int width = Math.max(1, (int) Math.round(original.getWidth() * scale));
    int height = Math.max(1, (int) Math.round(original.getHeight() * scale));

    return new int[] { width, height };
}

Feed those two numbers to either technique above. Taking Math.max of the ratios instead fills the box and overflows one dimension, which is what you want when you intend to crop the overflow away. The Math.min(scale, 1.0) line keeps small images from being enlarged and going soft.

How Do You Resize a Batch of Images in Java?

A BufferedImage and its Graphics2D object have to stay inside one thread, so each task creates its own pair. The resize call below is the read, draw and write sequence from the QuickResize class above, moved into a method that takes a source path, a target path and the two dimensions.

ExecutorService pool = Executors.newFixedThreadPool(
        Runtime.getRuntime().availableProcessors());

try (Stream<Path> files = Files.list(sourceDir)) {
    files.filter(Files::isRegularFile).forEach(image -> pool.submit(() -> {
        try {
            resize(image, targetDir.resolve(image.getFileName()), 800, 500);
        } catch (IOException e) {
            System.err.println("Skipped " + image + ": " + e.getMessage());
        }
    }));
}

pool.shutdown();
pool.awaitTermination(1, TimeUnit.HOURS);

Watch the heap while you do this. A decoded BufferedImage costs roughly its width times its height times the bytes per pixel, whatever the compressed size on disk was: a 6000 x 4000 photograph held as TYPE_INT_ARGB is 24 million pixels at 4 bytes each, about 96 MB, and a pool sized to an eight-core machine can hold eight of those at once. Size the pool against your heap rather than your core count when the inputs are large.

Java Image Resizing Libraries and Services Compared

Three open-source libraries wrap the code above, and a media platform replaces it. Here is what each asks of you, with the coordinates currently published on Maven Central:

Option Maven coordinates Aspect ratio Time reported by Baeldung Suited to
java.awt.Graphics2D None, it is in the JDK You calculate it 34 ms Server-side and batch work, anything where throughput matters
Image.getScaledInstance() None, it is in the JDK Pass a negative value 235 ms A one-off script where brevity beats speed
imgscalr org.imgscalr:imgscalr-lib:4.2 Handled for you 143 ms A quality setting you can dial without writing hint code
Thumbnailator net.coobird:thumbnailator:0.4.20 Handled for you 547 ms Thumbnails and directory work in very little code
Marvin com.github.downgoon:marvin:1.5.5 Handled for you 361 ms Resizing alongside crop, rotate, skew and filter operations
Cloudinary com.cloudinary:cloudinary-http5:2.3.0 Handled for you Not comparable, the work is off your servers Many sizes of one image, subject-aware cropping, no local CPU cost

The times are Baeldung’s, scaling one 1920 x 1920 pixel image down to 200 x 200 pixels. They are single measurements on one machine rather than a benchmark suite, so the ordering is the useful part: Graphics2D is the primitive the others are built on.

Frequently Asked Questions

How do I resize an image in Java without losing quality?

Set KEY_INTERPOLATION to VALUE_INTERPOLATION_BICUBIC and KEY_RENDERING to VALUE_RENDER_QUALITY before drawImage(), or pass Image.SCALE_SMOOTH to getScaledInstance(). Some loss is unavoidable when you remove pixels, and no setting recovers detail when you scale up, because the added pixels are interpolated rather than captured.

Which is faster, Graphics2D or getScaledInstance()?

Graphics2D. In Baeldung’s measurement on a 1920 x 1920 image scaled down to 200 x 200, Graphics2D took 34 ms against 235 ms for getScaledInstance().

Why does my resized JPEG have a black background?

JPEG has no alpha channel, and flattening a transparent source without filling first leaves those regions black. Fill the destination with a solid color before drawImage() whenever the output format cannot store alpha.

Why is my resized image rotated?

Resizing does not read EXIF orientation. ImageIO hands you the pixels as stored, so a photograph your file browser shows upright can come out on its side. Read the orientation tag separately and rotate before you scale.

QUICK TIPS
Tamas Piros
Cloudinary Logo Tamas Piros

In my experience, here are tips that can help you better resize images in Java:

  1. Use Image.SCALE_SMOOTH for better quality
    When resizing images with getScaledInstance(), use Image.SCALE_SMOOTH instead of Image.SCALE_DEFAULT to improve the image quality. This algorithm applies a better interpolation method for smoother resizing, particularly when reducing image size.
  2. Leverage AffineTransform for precise transformations
    For more complex resizing operations, use AffineTransform with the Graphics2D class. This allows you to scale images with fine-grained control over rotation, scaling, and translation, preserving quality even during drastic size changes.
  3. Use BufferedImage.TYPE_INT_ARGB for transparency
    When resizing images that include transparency (e.g., PNG images), use BufferedImage.TYPE_INT_ARGB to preserve the alpha channel during the resize operation. This ensures that any transparency in the original image is maintained in the resized version.
  4. Ensure thread-safety when resizing in parallel
    If resizing images in parallel (e.g., in a web application), be cautious about thread safety. Each BufferedImage and Graphics2D operation should be isolated within its own thread to prevent race conditions or unexpected behavior in multithreaded environments.
  5. Apply anti-aliasing for sharper images
    Before drawing images with Graphics2D, enable anti-aliasing with g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);. This improves the quality of the resized image by smoothing out jagged edges, especially on diagonals or curves.
  6. Use drawImage() with RenderingHints for quality control
    Combine drawImage() with RenderingHints to fine-tune how images are scaled. For example, use RenderingHints.KEY_INTERPOLATION with RenderingHints.VALUE_INTERPOLATION_BICUBIC for high-quality image scaling when performance isn’t the top priority.
  7. Resize proportionally to maintain aspect ratio
    Always calculate the resized image dimensions proportionally to maintain the original aspect ratio. For example, if resizing based on width, calculate the height as newHeight = (originalHeight / originalWidth) * newWidth to avoid distortion.
  8. Implement caching for resized images
    If resizing the same images frequently, implement a caching mechanism to store resized versions. This saves time and processing power by preventing repeated resizing operations on the same image.
  9. Utilize Graphics2D double buffering for smoother drawing
    When working with images in a UI, enable double buffering to reduce flickering and improve performance when resizing images dynamically. This can be done with JComponent.setDoubleBuffered(true).
  10. Offload large-scale resizing to Cloudinary
    For applications dealing with large volumes of images, offload resizing tasks to Cloudinary. It automatically handles resizing, cropping, and optimization with its API, and can apply AI-based cropping to focus on the most important part of the image, improving performance and reducing server load.

These advanced techniques will help you optimize image resizing in Java, ensuring better quality, performance, and scalability in your projects.

Last updated: Nov 4, 2026
★★★★★
4.7 (21 reviews)
Talk to Sales Talk to Sales