All formats

ImageIO

LanguageJava (part of the JDK, java.desktop module)
LicenseGPL v2 with Classpath Exception (OpenJDK)
Repositorygithub.com/openjdk/jdk
Documentationjavax.imageio API, PNG metadata format
Depends onnothing (built into the JDK)
Read / writeyes / yes, all color types and bit depths, all standard chunks through the metadata API

ImageIO is the image I/O API of the Java standard library. It reads and writes PNG, JPEG, GIF, BMP, WBMP and TIFF without any dependency. ImageIO.read returns a java.awt.image.BufferedImage that you can draw on with Graphics2D.

For simple load and save it’s one line. Metadata (text chunks, pHYs, iCCP) goes through IIOMetadata, a DOM tree that is verbose but complete. ImageIO loads the whole image into memory; for very large PNG files use PNGJ. ImageIO isn’t available on Android.

Installation#

Nothing to install: javax.imageio is in every JDK. In a modular project add requires java.desktop; to module-info.java.

Basic usage: read and write a PNG#

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

public class PngExample {
    public static void main(String[] args) throws IOException {
        BufferedImage image = ImageIO.read(new File("in.png"));
        if (image == null) {
            throw new IOException("not a supported image");
        }
        System.out.println(image.getWidth() + " x " + image.getHeight()
                + ", alpha: " + image.getColorModel().hasAlpha());

        // set the top-left pixel to opaque red (ARGB)
        image.setRGB(0, 0, 0xFFFF0000);

        if (!ImageIO.write(image, "png", new File("out.png"))) {
            throw new IOException("no PNG writer");
        }
    }
}

How to get PNG width and height without decoding#

An ImageReader reads the header on request, without decoding pixels:

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.png"))) {
    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 resize a PNG#

Java
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

static BufferedImage resize(BufferedImage src, int width, int height) {
    BufferedImage dst = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = dst.createGraphics();
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g.drawImage(src, 0, 0, width, height, null);
    g.dispose();
    return dst;
}

How to set PNG compression level#

Since Java 9 the PNG writer accepts a compression quality: 0.0f is the smallest file (DEFLATE level 9), 1.0f is no compression:

Java
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

static void writeSmallest(BufferedImage image, File file) throws IOException {
    ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next();
    ImageWriteParam param = writer.getDefaultWriteParam();
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionQuality(0.0f);
    try (ImageOutputStream out = ImageIO.createImageOutputStream(file)) {
        writer.setOutput(out);
        writer.write(null, new IIOImage(image, null, null), param);
    } finally {
        writer.dispose();
    }
}

How to read PNG text chunks#

Text chunks are in the native metadata tree (javax_imageio_png_1.0) under tEXt, zTXt and iTXt:

Java
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.File;

try (ImageInputStream in = ImageIO.createImageInputStream(new File("in.png"))) {
    ImageReader reader = ImageIO.getImageReadersByFormatName("png").next();
    reader.setInput(in);
    IIOMetadata metadata = reader.getImageMetadata(0);
    Node root = metadata.getAsTree("javax_imageio_png_1.0");
    NodeList entries = ((Element) root).getElementsByTagName("tEXtEntry");
    for (int i = 0; i < entries.getLength(); i++) {
        Element e = (Element) entries.item(i);
        System.out.println(e.getAttribute("keyword") + ": " + e.getAttribute("value"));
    }
    reader.dispose();
}

How to convert PNG to JPEG#

The JPEG writer fails on images with alpha. Draw onto an RGB image with a white background first:

Java
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;

BufferedImage png = ImageIO.read(new File("in.png"));
BufferedImage rgb = new BufferedImage(png.getWidth(), png.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = rgb.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, png.getWidth(), png.getHeight());
g.drawImage(png, 0, 0, null);
g.dispose();
ImageIO.write(rgb, "jpg", new File("out.jpg"));

Tips#