# TwelveMonkeys ImageIO: image formats the JDK refuses to read

> A Java plugin collection that extends ImageIO with readers and writers for PSD, TIFF, WebP, PICT, ICNS, DDS and dozens of legacy formats, published under one Maven coordinate and still shipping patch releases.

**haraldk/TwelveMonkeys** — TwelveMonkeys ImageIO: Additional plug-ins and extensions for Java's ImageIO

- Repository: https://github.com/haraldk/TwelveMonkeys
- Website: https://haraldk.github.io/TwelveMonkeys/
- Stars: 2,147 · Forks: 327
- Language: Java
- License: BSD-3-Clause
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/haraldk-twelvemonkeys

## What a javax.imageio plugin actually changes

Java's ImageIO is a service-provider system. A format is supported because some class on the classpath declares itself a reader or writer SPI for that format, and the JDK ships a small set of those for the formats it covers. Adding a plugin does not replace anything; it appends to the list that `ImageIO.getImageReadersByFormatName` searches.

The README states this framing directly, describing the project as extended image file format support for the Java platform through plugins for the `javax.imageio.*` package. The stated goal is narrower and more interesting than a general imaging library: support for formats not covered by the JDK, so that data found in the wild can be read and legacy formats stay accessible. The project says it sees a need for open implementations of readers for popular formats, which is a fair description of why a PSD or PICT reader exists at all rather than being written per application.

That framing has a practical consequence. If your code already calls `ImageIO.read`, adding the dependency is often the entire integration. There is no new API to learn and no wrapper type to thread through your pipeline. What changes is which implementations are found.

## Format coverage, and which direction each one works

The README's plugin table is the real specification, and it separates reading from writing, which is the detail most summaries leave out. Only some formats are symmetric.

| Format | Read | Write | Notes |
| --- | --- | --- | --- |
| BMP | yes | yes | native and standard metadata |
| ICO | yes | yes | MS Windows icon format |
| ICNS | yes | yes | Apple icon image |
| IFF | yes | yes | Amiga and EA interchange |
| JPEG | yes | yes | native and standard metadata |
| PICT | yes | yes | Apple QuickTime picture |
| PAM, PPM | yes | yes | NetPBM variants |
| DDS | yes | no | MS Direct Draw Surface |
| HDR | yes | no | Radiance RGBE |
| PCX, DCX | yes | no | ZSoft Paintbrush, multi-page fax |
| CUR | yes | no | MS Windows cursor |
| PBM, PGM, PFM | yes | no | read only variants |
| SVG, WMF | yes | no | requires Batik |

Reading is the priority across the board, which fits the stated goal of handling what arrives from elsewhere. If your use case is converting legacy files into a modern format, the write column is the one to read, and it is shorter than the read column.

The SVG and WMF rows carry a dependency on Apache Batik, the project's SVG implementation. That is the one place where adding TwelveMonkeys pulls in a second substantial library, and it is worth knowing before you add the dependency for a PDF pipeline and discover a vector rendering stack arriving with it.

## What is in the repository beyond imageio/

The top-level tree is small enough to read in one pass, and the README does not document the split:

```bash
bom/
common/
contrib/
imageio/
servlet/
pom.xml
LICENSE.txt
SECURITY.md
```

The plugin implementations live under `imageio/`, which is also the artifact the README's badges point at, published under the group id `com.twelvemonkeys.imageio`. Alongside it are a `bom/` for dependency management, a `common/` module, a `contrib/` directory, and a `servlet/` directory that is presumably for server-side use. This layout is named rather than explained, so anyone planning to depend on more than the main artifact is working from the project site rather than the README.

Two root files are worth noting for how the project is run. `SECURITY.md` exists, which tells you where a vulnerability report goes, and the badge row at the top of the README shows CI, CodeQL, an OpenSSF Scorecard badge and an OpenSSF Best Practices badge. Static analysis and a published security posture are visible from the README rather than buried in a wiki, which is a reasonable signal for a library that parses untrusted files.

There is also a Stack Overflow tag badge for `twelvemonkeys`, which is where the practical knowledge sits. A format parser question usually has a real answer there, and it is more likely to be answered there than on an issue tracker.

## Metadata support, which is the part people underrate

Look at the metadata column rather than the read and write columns. Several formats list both native and standard metadata: BMP, JPEG, DDS, HDR, IFF, PCX, DCX, PICT and the NetPBM variants all point at the JDK's standard metadata tree, and BMP and JPEG additionally list native metadata. The remaining formats, including ICO, ICNS, CUR, PNTG, SVG and WMF, list no metadata support at all.

That distinction decides whether a plugin is usable for your job. If you are building a thumbnail pipeline that only needs pixels, metadata support is irrelevant. If you need to read an ICC profile, a DPI value, or the EXIF block on a JPEG, then a reader that returns a `BufferedImage` and drops everything else is not enough, and the standard metadata entries are what let you get at that data through the normal ImageIO tree rather than by casting to a vendor class.

ICC profiles are worth calling out because they come up constantly in print and photography work, and the repository's own topics list includes `icc-profiles`. A plugin that reports standard metadata is what lets you walk the standard metadata tree and find the profile node. The formats with no metadata column are the ones where you should assume the pixel data is all you get.

The project also carries a `common/` module, which is a reasonable place for format-independent handling such as colour space conversion, though the README does not say what is in it.

## What the 3.15 releases say about the code

Three releases in September 2026 tell you more about how this project is maintained than any badge does.

Version 3.15.0, published 2026-09-06, is the substantial one. Its notes describe it as finally fixing long-standing WebP decoding issues, along with TIFF CCITT and fax decoding issues, and adding stricter memory allocation guards to avoid running out of memory. The itemised changes are mostly input validation: rejecting PCX bit-plane counts over 8, clamping an x delta to row bounds in the BMP RLE8 decoder, validating an item id and bounding filename length in the ThumbsDB catalog, quoting a namespace prefix before a regex match in the SVG reader, and creating temp cache files with owner-only permissions.

Versions 3.15.1 (2026-09-15) and 3.15.2 (2026-09-18) are both labelled bug fix releases. 3.15.1 rejects an out-of-range palette register in an IFF multipalette color map and bounds opcode payload skipping in PICT. 3.15.2 keeps alpha and image type consistent for a null destination in ResampleOp and avoids an infinite loop and allocation issues in the PSD reader.

Read as a group, those notes describe a parser being hardened against hostile input, which is exactly the failure mode of a format reader. An infinite loop in a PSD reader, an unbounded allocation, and an out-of-range palette index are all the shapes of defect that turn a malformed upload into a stuck thread, so the fact that they keep getting fixed says something about what these readers get pointed at. The repository is not archived and the last push was on 2026-09-25, so this hardening is ongoing rather than finished.

One thing the release notes show is that most of this work comes from contributors other than the maintainer, with several changes credited to arib06 and one to a contributor outside the project.

## Where TwelveMonkeys is the wrong dependency

There are two honest reasons to skip it.

The first is performance. A plugin reader is not faster than the JDK's own reader for formats the JDK already handles, and for the formats it does not handle there is no JDK reader to be slow. If your pipeline is dominated by large JPEGs or PNGs from a trusted source, adding this library buys you nothing and costs you a classpath entry. The plugins pay off at the edges, where files arrive in formats you did not choose.

The second is scope. This is a plugin collection, not an imaging framework. It does not do resizing pipelines, colour management policy, or anything about how your application stores images. TwelveMonkeys mentions ResampleOp in its release notes, but that is a fix to an existing operation rather than a claim to be a full imaging library. If you need the whole pipeline, Apache Commons Imaging or a commercial toolkit is the comparison to make, and the difference is that those give you operations this project deliberately does not have.

On licensing it is BSD 3-Clause, which is permissive, with `LICENSE.txt` at the repository root. There is no copyleft obligation to worry about when you embed it in a commercial product, though Batik arrives under the Apache License 2.0 if you use the SVG or WMF readers, and Apache 2.0 carries its own notice requirements.

## Conclusion

TwelveMonkeys earns its place in any Java service that accepts images from outside its control, because the alternative to a plugin is either a rejected upload or a hand-written parser per format. What it does not do is decode faster than the JDK or replace ImageIO, and the formats it refuses to read, plus the fact that SVG and WMF drag in Batik, are worth checking against your file list first. The fastest way to confirm fit is to run ImageIO.scanForPlugins against your actual sample files and see which reader SPI claims each one; the plugin table in the README tells you the formats, but only your files tell you the version and colour model you will get back.

## FAQ

### What formats does TwelveMonkeys ImageIO add to Java?

The README's plugin table lists readers and writers for BMP, JPEG, ICO, ICNS, IFF, PICT, the NetPBM formats, and readers for PCX, DCX, DDS, HDR, CUR, PFM and PNTG. SVG and WMF are read-only and require Apache Batik. Release notes also cover PSD and WebP.

### What Maven dependency do I need for TwelveMonkeys ImageIO?

The README's badges point at the artifact published under the group id com.twelvemonkeys.imageio, with the main artifact named imageio. The repository also contains a bom module, which is the usual way to keep the version aligned across the related artifacts.

### Can TwelveMonkeys write PSD or PICT files, or only read them?

The plugin table marks PICT as both readable and writable. PSD does not appear in the table, and the PSD work in the 3.15.2 release notes is a fix to an infinite loop and allocation issues in the reader, which indicates read support rather than writing.

### Does TwelveMonkeys read ICC profiles and EXIF metadata?

Several formats list both native and standard metadata in the plugin table, including JPEG and BMP, and standard metadata is what exposes the colour and profile nodes through the normal ImageIO metadata tree. Formats listed with no metadata support, such as ICO, ICNS, CUR and SVG, return the pixel data without it.

## Sources

- [haraldk/TwelveMonkeys on GitHub](https://github.com/haraldk/TwelveMonkeys)
- [License: BSD-3-Clause](https://github.com/haraldk/TwelveMonkeys/blob/master/LICENSE)
- [Project website](https://haraldk.github.io/TwelveMonkeys/)
- [README](https://github.com/haraldk/TwelveMonkeys/blob/master/README.md)
- [Releases](https://github.com/haraldk/TwelveMonkeys/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/haraldk-twelvemonkeys
