Java ImageIO
Last modified: July 17, 2026
This Java ImageIO tutorial shows how to read and write images using the
javax.imageio package. We cover reading and writing images,
format conversion, image scaling, working with thumbnails, using
ImageReader and ImageWriter for advanced control,
and reading image metadata.
Image I/O
The javax.imageio package provides a plug-in based framework
for reading and writing images in Java. It supports a wide range of image
formats through standard and third-party plug-ins. The central class is
ImageIO, which offers static convenience methods for common
operations.
The Java Image I/O API is organised around the following key abstractions:
| Class / Interface | Purpose |
|---|---|
ImageIO |
Static convenience methods for reading, writing, and format detection |
ImageReader |
Decodes images from a stream or file with fine-grained control |
ImageWriter |
Encodes images to a stream or file with fine-grained control |
ImageReadParam |
Specifies how a stream should be decoded (source region, subsampling, etc.) |
ImageWriteParam |
Specifies how an image should be encoded (compression, tiling, etc.) |
IIOImage |
Container for an image, optional thumbnails, and metadata |
ImageTypeSpecifier |
Describes the colour model and sample model of an image |
The standard Java runtime includes built-in plug-ins for BMP, GIF, JPEG, PNG, TIFF, and WBMP image formats.
Reading an image from a file
The simplest way to read an image is using the
ImageIO.read(File) method, which returns a
BufferedImage.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
void main() {
try {
BufferedImage image = ImageIO.read(new File("image.png"));
System.out.println("Image read successfully");
System.out.printf("Width: %d, Height: %d%n",
image.getWidth(), image.getHeight());
} catch (IOException e) {
System.err.println("Error reading image: " + e.getMessage());
}
}
The ImageIO.read method automatically detects the image format
by examining the file header. It returns a BufferedImage that
can be used for further processing or display.
$ java Main.java Image read successfully Width: 800, Height: 600
Reading an image from an InputStream
Images can also be read from an InputStream, which is useful
when the image data comes from a network source or a byte array.
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.imageio.ImageIO;
void main() {
try {
byte[] imageBytes = Files.readAllBytes(Path.of("image.png"));
InputStream is = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(is);
System.out.printf("Width: %d, Height: %d%n",
image.getWidth(), image.getHeight());
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
We read the image file into a byte array, wrap it in a
ByteArrayInputStream, and pass it to ImageIO.read.
$ java Main.java Width: 800, Height: 600
Writing an image to a file
The ImageIO.write method encodes a BufferedImage
to the specified format and writes it to a file.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
void main() {
try {
int width = 200;
int height = 200;
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
// Fill with red
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
image.setRGB(x, y, 0xFF0000);
}
}
File output = new File("red_square.png");
ImageIO.write(image, "png", output);
System.out.println("Image written to " + output.getPath());
} catch (IOException e) {
System.err.println("Failed to write image: " + e.getMessage());
}
}
We create a 200x200 red square image programmatically and write it to a
PNG file using ImageIO.write. The second parameter specifies
the format name ("png", "jpg", "gif", "bmp", "tiff").
$ java Main.java Image written to red_square.png
Format conversion
A common task is converting an image from one format to another. This is easily done by reading the image with one format and writing it with another.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
void main() {
try {
BufferedImage image = ImageIO.read(new File("photo.jpg"));
File output = new File("photo.png");
ImageIO.write(image, "png", output);
System.out.println("Converted JPG to PNG successfully");
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
We read a JPEG file and write it as a PNG. The Image I/O API handles all necessary transcoding internally. This approach works for any pair of supported formats.
$ java Main.java Converted JPG to PNG successfully
Scaling an image
When reading an image, we can scale it to a desired dimension. The following example reads an image and scales it to a fixed width while preserving the aspect ratio.
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
void main() {
try {
BufferedImage source = ImageIO.read(new File("photo.jpg"));
if (source == null) {
System.err.println("Failed to read image. Unsupported format?");
return;
}
int targetWidth = 300;
int targetHeight = (int) ((double) source.getHeight()
/ source.getWidth() * targetWidth);
BufferedImage scaled = new BufferedImage(targetWidth, targetHeight,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = scaled.createGraphics();
try {
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(source, 0, 0, targetWidth, targetHeight, null);
} finally {
g2d.dispose();
}
ImageIO.write(scaled, "jpg", new File("photo_scaled.jpg"));
System.out.println("Scaled image written successfully");
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
We calculate the target height to preserve the aspect ratio based on the
target width. The Graphics2D.drawImage method performs the
scaling with bilinear interpolation for smooth results.
The RenderingHints.KEY_INTERPOLATION hint controls how pixels
are calculated during scaling:
- Nearest neighbor (
VALUE_INTERPOLATION_NEAREST_NEIGHBOR): lowest quality, picks the single closest pixel; produces blocky or jagged results when scaling up - Bilinear (
VALUE_INTERPOLATION_BILINEAR): medium quality, weighted average of the 2×2 pixel neighborhood; smooth but slightly soft - Bicubic (
VALUE_INTERPOLATION_BICUBIC): highest quality, weighted average of the 4×4 pixel neighborhood; sharper than bilinear, more computationally expensive
Writing with compression level
For formats that support compression (such as JPEG), we can control the
compression quality using ImageWriteParam.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
void main() {
try {
BufferedImage image = ImageIO.read(new File("photo.jpg"));
Iterator<ImageWriter> writers =
ImageIO.getImageWritersByFormatName("jpg");
if (!writers.hasNext()) {
System.err.println("No writer found");
return;
}
ImageWriter writer = writers.next();
try {
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.3f);
File output = new File("photo_low.jpg");
try (ImageOutputStream ios = ImageIO.createImageOutputStream(output)) {
writer.setOutput(ios);
writer.write(null, new IIOImage(image, null, null), param);
}
System.out.println("Written with compression quality 0.3");
} finally {
writer.dispose();
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
We obtain an ImageWriter for the JPEG format, configure the
write param with explicit compression mode and a quality setting of 0.3
(lower means smaller file size but lower quality), and write the image.
$ java Main.java Written with compression quality 0.3
Using ImageReader for fine-grained control
For advanced reading operations, such as reading a specific region or
subsampling, we can use ImageReader directly.
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
void main() {
try {
File file = new File("photo.jpg");
try (ImageInputStream iis = ImageIO.createImageInputStream(file)) {
Iterator<ImageReader> readers =
ImageIO.getImageReaders(iis);
if (!readers.hasNext()) {
System.err.println("No reader found");
return;
}
ImageReader reader = readers.next();
try {
reader.setInput(iis);
// Read only the top-left 200x200 region
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(new Rectangle(0, 0, 200, 200));
BufferedImage region = reader.read(0, param);
ImageIO.write(region, "jpg", new File("region.jpg"));
System.out.printf("Region image: %dx%d%n",
region.getWidth(), region.getHeight());
} finally {
reader.dispose();
}
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
We use ImageReader to read only a 200x200 region from the
top-left corner of the image, without loading the entire image into memory.
The setSourceRegion method on ImageReadParam
controls which portion of the image is decoded.
$ java Main.java Region image: 200x200
Reading image thumbnails
Some image formats (such as JPEG) can embed thumbnail previews. The
ImageReader can read these thumbnails without decoding the
full image.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
void main() {
try {
File file = new File("photo.jpg");
try (ImageInputStream iis = ImageIO.createImageInputStream(file)) {
Iterator<ImageReader> readers =
ImageIO.getImageReaders(iis);
if (!readers.hasNext()) {
System.err.println("No reader found");
return;
}
ImageReader reader = readers.next();
try {
reader.setInput(iis);
int numThumbs = reader.getNumThumbnails(0);
System.out.printf("Number of thumbnails: %d%n", numThumbs);
if (numThumbs > 0) {
BufferedImage thumb = reader.readThumbnail(0, 0);
System.out.printf("Thumbnail size: %dx%d%n",
thumb.getWidth(), thumb.getHeight());
}
} finally {
reader.dispose();
}
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
The getNumThumbnails method returns the number of embedded
thumbnails for the given image index. readThumbnail reads a
specific thumbnail without decoding the full-resolution image.
$ java Main.java Number of thumbnails: 1 Thumbnail size: 160x120
Reading image metadata
Image metadata contains information such as the image dimensions, colour space, compression type, and format-specific details (like EXIF data in JPEG).
void main() {
File file = new File("photo.jpg");
try (ImageInputStream iis = ImageIO.createImageInputStream(file)) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
if (!readers.hasNext()) {
System.err.println("No reader found");
return;
}
ImageReader reader = readers.next();
try {
reader.setInput(iis);
IIOMetadata metadata = reader.getImageMetadata(0);
System.out.println("Available metadata formats:");
for (String name : metadata.getMetadataFormatNames()) {
System.out.println(" " + name);
}
} finally {
reader.dispose();
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
The getImageMetadata method returns an IIOMetadata
object containing format-specific metadata for the given image index. The
getMetadataFormatNames method lists the available metadata
representation formats (e.g., standard, native).
$ java Main.java Available metadata formats: javax_imageio_jpeg_image_1.0 javax_imageio_1.0
Listing available readers and writers
The ImageIO class provides methods to discover which image
format plug-ins are available in the current runtime.
import java.util.Arrays;
import javax.imageio.ImageIO;
void main() {
String[] readerFormats = ImageIO.getReaderFormatNames();
String[] writerFormats = ImageIO.getWriterFormatNames();
System.out.println("Supported read formats:");
System.out.println(" " + Arrays.toString(readerFormats));
System.out.println("Supported write formats:");
System.out.println(" " + Arrays.toString(writerFormats));
System.out.println();
System.out.printf("Number of read formats: %d%n",
readerFormats.length);
System.out.printf("Number of write formats: %d%n",
writerFormats.length);
}
getReaderFormatNames and getWriterFormatNames
return the format names (e.g., "jpg", "png") that the current runtime
supports for reading and writing.
$ java Main.java Supported read formats: [JPG, jpg, tiff, bmp, BMP, gif, GIF, WBMP, png, PNG, JPEG, tif, TIF, TIFF, wbmp, jpeg] Supported write formats: [JPG, jpg, tiff, bmp, BMP, gif, GIF, WBMP, png, PNG, JPEG, tif, TIF, TIFF, wbmp, jpeg] Number of read formats: 16 Number of write formats: 16
Source
Java ImageIO - Language Reference
In this article, we have worked with the Java Image I/O API.
Author
List all Java tutorials.