All formats

ImageIO

LanguageJava (part of the JDK)
LicenseGPL-2.0 with Classpath Exception (OpenJDK)
Repositorygithub.com/openjdk/jdk (java.desktop module)
Documentationjavax.imageio, JPEG metadata format
Depends onnothing (bundled native libjpeg 6b)
Read / writeyes / 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#

Java
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#

Java
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#

Java
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:

Java
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:

Java
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#