TwelveMonkeys ImageIO
| Language | Java 8 or later |
|---|---|
| License | BSD 3-Clause |
| Repository | github.com/haraldk/TwelveMonkeys |
| Documentation | BMP plugin wiki, README |
| Depends on | TwelveMonkeys imageio-core and common-* modules (pulled in by Maven) |
| Read / write | yes, all known Windows and OS/2 versions, RLE4, RLE8, embedded PNG and JPEG / yes, 32-bit with alpha from TYPE_4BYTE_ABGR images |
TwelveMonkeys is a collection of plugins for javax.imageio. Once the jar is on the classpath, the standard ImageIO.read call uses it, so existing code gets better format support without changes. Its imageio-bmp module reads every BMP variant, including the ones the JDK reader rejects, and adds ICO (icons) and CUR (cursors), which store images as BMP data.
Use it when you process BMP files from many sources (scanners, old software, icon extraction). Its BMP writer is limited: it only accepts 4-byte ABGR images and writes them as 32-bit; other image types still go to the JDK writer. The project also has plugins for JPEG (CMYK), TIFF, WebP, PSD, PICT, SGI and more.
Installation#
Maven:
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-bmp</artifactId>
<version>3.15.3</version>
</dependency>
Gradle:
implementation 'com.twelvemonkeys.imageio:imageio-bmp:3.15.3'
In web applications, also register com.twelvemonkeys.servlet.image.IIOProviderContextListener (artifact com.twelvemonkeys.servlet:servlet) so plugins load and unload with the application.
Basic usage: read a BMP#
Nothing changes in your code; ImageIO finds the plugin through the service loader:
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ReadBmp {
public static void main(String[] args) throws IOException {
BufferedImage image = ImageIO.read(new File("in.bmp"));
if (image == null) {
throw new IOException("not a supported image");
}
System.out.println(image.getWidth() + " x " + image.getHeight()
+ ", alpha: " + image.getColorModel().hasAlpha());
ImageIO.write(image, "png", new File("out.png"));
}
}
How to check that the TwelveMonkeys reader is used#
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import java.util.Iterator;
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("bmp");
while (readers.hasNext()) {
System.out.println(readers.next().getClass().getName());
// com.twelvemonkeys.imageio.plugins.bmp.BMPImageReader comes first
}
How to write a 32-bit BMP with alpha#
The JDK writer refuses images with alpha. TwelveMonkeys writes TYPE_4BYTE_ABGR images as 32-bit BMP:
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
BufferedImage src = ImageIO.read(new File("in.png"));
BufferedImage abgr = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
abgr.getGraphics().drawImage(src, 0, 0, null);
if (!ImageIO.write(abgr, "bmp", new File("alpha.bmp"))) {
throw new IllegalStateException("no BMP writer");
}
How to read all images from an ICO file#
An ICO file holds the same icon in several sizes. ImageIO.read returns only the first; use an ImageReader to get all of them:
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.File;
try (ImageInputStream in = ImageIO.createImageInputStream(new File("app.ico"))) {
ImageReader reader = ImageIO.getImageReadersByFormatName("ico").next();
reader.setInput(in);
int count = reader.getNumImages(true);
for (int i = 0; i < count; i++) {
BufferedImage icon = reader.read(i);
System.out.println(icon.getWidth() + " x " + icon.getHeight());
}
reader.dispose();
}
Tips#
- The plugins register themselves through
META-INF/services; in a shaded (fat) jar, merge the service files or the plugins won’t load. - With TwelveMonkeys installed, both its BMP reader and the JDK one are registered; TwelveMonkeys takes priority.
- Add
imageio-webp,imageio-tifforimageio-psdfrom the same project for more formats.