ImageIO
| Language | Java (part of the JDK) |
|---|---|
| License | GPL-2.0 with Classpath Exception (OpenJDK) |
| Repository | github.com/openjdk/jdk (java.desktop module) |
| Documentation | javax.imageio, JPEG metadata format |
| Depends on | nothing (bundled native libjpeg 6b) |
| Read / write | yes / yes; baseline and progressive, grayscale and YCbCr; no CMYK/YCCK, no Exif parsing |
ImageIO is the image I/O API of the JDK. ImageIO.read and ImageIO.write handle JPEG in one line each; ImageReader and ImageWriter give access to quality, progressive mode, metadata trees and reading parts of an image. Since Java 9 the java.desktop module includes JPEG, PNG, GIF, BMP, WBMP and TIFF.
Known limits of the JDK JPEG code: it throws IIOException: Unsupported Image Type on CMYK and YCCK files, ignores the Exif orientation, and since Java 11 refuses to write images with alpha (“Bogus input colorspace”). Add TwelveMonkeys to fix the reading problems.
Installation#
Nothing to install. In a modular application, add requires java.desktop; to module-info.java. On servers, run with -Djava.awt.headless=true.
Basic usage: read, resize and write a JPEG#
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 ResizeJpeg {
public static void main(String[] args) throws IOException {
BufferedImage src = ImageIO.read(new File("in.jpg"));
if (src == null) throw new IOException("no reader for this file");
System.out.println(src.getWidth() + " x " + src.getHeight());
int w = 800, h = src.getHeight() * w / src.getWidth();
BufferedImage dst = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = dst.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawImage(src, 0, 0, w, h, null);
g.dispose();
if (!ImageIO.write(dst, "jpg", new File("out.jpg")))
throw new IOException("no JPEG writer");
}
}
ImageIO.write uses quality 0.75. To choose it, use an ImageWriter (below).
How to save a JPEG with a quality setting#
import javax.imageio.*;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
static void writeJpeg(BufferedImage image, File file, float quality) throws IOException {
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality); // 0.0 .. 1.0
param.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); // progressive; omit for baseline
try (ImageOutputStream out = ImageIO.createImageOutputStream(file)) {
writer.setOutput(out);
writer.write(null, new IIOImage(image, null, null), param);
} finally {
writer.dispose();
}
}
How to get JPEG width and height without decoding#
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.io.File;
import java.util.Iterator;
try (ImageInputStream in = ImageIO.createImageInputStream(new File("in.jpg"))) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
System.out.println(reader.getWidth(0) + " x " + reader.getHeight(0));
} finally {
reader.dispose();
}
}
}
How to convert PNG with transparency to JPEG#
Draw the image on an opaque RGB image first; writing an ARGB image to JPEG throws an exception:
BufferedImage png = ImageIO.read(new File("logo.png"));
BufferedImage rgb = new BufferedImage(png.getWidth(), png.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = rgb.createGraphics();
g.setColor(java.awt.Color.WHITE);
g.fillRect(0, 0, rgb.getWidth(), rgb.getHeight());
g.drawImage(png, 0, 0, null);
g.dispose();
ImageIO.write(rgb, "jpg", new File("logo.jpg"));
How to decode a large JPEG at lower resolution#
setSourceSubsampling makes the reader skip pixels while decoding, which uses much less memory than reading the full image and scaling it:
ImageReader reader = ImageIO.getImageReadersByFormatName("jpeg").next();
try (ImageInputStream in = ImageIO.createImageInputStream(new File("big.jpg"))) {
reader.setInput(in);
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceSubsampling(4, 4, 0, 0); // every 4th pixel in each direction
BufferedImage small = reader.read(0, param);
} finally {
reader.dispose();
}
Tips#
ImageIO.readreturnsnull(not an exception) when no reader recognizes the file.- The Exif block is in the metadata tree as an
unknownnode withMarkerTag="225"; parse it with metadata-extractor. ImageIO.setUseCache(false)avoids temporary files when reading from streams on servers.