FPNG Java¶
FPNG-Java provides Java wrappers around two native, SIMD-optimised PNG encoders — FPNG (SSE2) and FPNGE (AVX2). Both produce fully compliant PNG files at significantly higher throughput than javax.imageio.
The JDK23+ version of the encoders uses Foreign Function & Memory API and is the fastest. Otherwise JNI is used via JNA, which comes with some overhead.
Latest stable release: fpng-java-1.4.1.jar
GitHub Repository: https://github.com/manticore-projects/fpng-java
Features¶
- Two encoders with automatic runtime selection
FPNG — SSE2/SSE4.1/PCLMUL, works on any x86-64 CPU
FPNGE — AVX2, used automatically when the CPU supports it
FFM for JDK22+, JNI/JNA for older JDKs
Runtime
hasAVX2()CPUID probe — no AVX2 library is loaded on unsupported hardwareEncodes
BufferedImagedirectly — 3-channel (RGB) and 4-channel (RGBA)Handles Java’s native
TYPE_3BYTE_BGR/TYPE_4BYTE_ABGRchannel order in C via SIMD byte shufflesInterleaved Adler32 checksum — no redundant full-image pass
PCLMUL-accelerated CRC32
Supports
Java 8,Java 11,Java 17andJava 21Platforms: Linux x86-64, Windows x86/x86-64, macOS x86-64
Benchmarks¶
Run the JMH benchmarks with:
./gradlew jmh
Results are written to benchmark/build/results/jmh/results.json.
PNG Encoder Benchmark Report
3 ch example.png
| Encoder | Score (ms/op) | Error | vs Winner |
|---|---|---|---|
| FPNGE (Java 23 FFM) | 2.706 | ±0.143 | baseline |
| FPNGE (JNI) | 3.261 | ±0.691 | +20.5% |
| FPNG Encoder (JNI) | 3.987 | ±0.818 | +47.3% |
| FPNG Encoder (Java 23) | 5.002 | ±1.122 | +84.9% |
| PNGEncoder (fastest) | 20.986 | ±12.699 | +675.7% |
| ObjectPlanet PNG | 41.352 | ±2.925 | +1428.4% |
| PNGEncoder | 44.550 | ±23.990 | +1546.6% |
| ImageIO | 50.375 | ±4.578 | +1761.9% |
3 ch looklet-look-scale6.png
| Encoder | Score (ms/op) | Error | vs Winner |
|---|---|---|---|
| FPNGE (Java 23 FFM) | 139.807 | ±33.887 | baseline |
| FPNGE (JNI) | 166.635 | ±126.279 | +19.2% |
| FPNG Encoder (JNI) | 302.257 | ±141.186 | +116.2% |
| FPNG Encoder (Java 23) | 337.719 | ±28.268 | +141.6% |
| PNGEncoder (fastest) | 346.707 | ±111.700 | +148.0% |
| PNGEncoder | 1176.420 | ±115.739 | +741.5% |
| ImageIO | 1238.361 | ±568.947 | +785.8% |
| ObjectPlanet PNG | 1756.963 | ±427.382 | +1156.7% |
4 ch example.png
| Encoder | Score (ms/op) | Error | vs Winner |
|---|---|---|---|
| FPNGE (Java 23 FFM) | 4.223 | ±0.587 | baseline |
| FPNGE (JNI) | 4.625 | ±1.513 | +9.5% |
| FPNG Encoder (Java 23) | 6.605 | ±1.217 | +56.4% |
| FPNG Encoder (JNI) | 8.457 | ±2.726 | +100.3% |
| PNGEncoder (fastest) | 24.527 | ±21.807 | +480.9% |
| PNGEncoder | 50.895 | ±4.062 | +1105.3% |
| ObjectPlanet PNG | 51.795 | ±24.218 | +1126.6% |
| ImageIO | 63.420 | ±37.017 | +1401.9% |
4 ch looklet-look-scale6.png
| Encoder | Score (ms/op) | Error | vs Winner |
|---|---|---|---|
| FPNGE (Java 23 FFM) | 197.625 | ±39.119 | baseline |
| FPNGE (JNI) | 271.884 | ±56.459 | +37.6% |
| PNGEncoder (fastest) | 423.605 | ±168.635 | +114.3% |
| FPNG Encoder (Java 23) | 440.591 | ±53.450 | +122.9% |
| FPNG Encoder (JNI) | 476.420 | ±445.912 | +141.1% |
| ImageIO | 1484.558 | ±1000.757 | +651.2% |
| PNGEncoder | 1511.124 | ±147.042 | +664.6% |
| ObjectPlanet PNG | 2145.475 | ±202.674 | +985.6% |