FPNG Java

FPNG-Java provides Java wrappers around three native, SIMD-optimised PNG encoders — FPNG (SSE2), FPNGE (AVX2), and ZPNG (zlib-ng). All produce fully compliant PNG files at significantly higher throughput than javax.imageio.

The three encoders solve different problems:

  • FPNG and FPNGE are tuned for photographic content and raw throughput. They use minimal-effort deflate via lookup tables, producing large files very fast.

  • ZPNG uses zlib-ng’s full deflate implementation and is tuned for screen content (UI screenshots, dashboards, remote-desktop tiles, anything with sharp edges and large flat-colour regions). It produces files about half the size of FPNG/FPNGE on this kind of input, at roughly 2-3× the encoding cost. For bandwidth-constrained delivery this is the right trade.

The JDK22+ 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-2.1.jar

GitHub Repository: https://github.com/manticore-projects/fpng-java

Features

  • Three encoders, each tuned for a different workload
    • FPNG — SSE2/SSE4.1/PCLMUL, works on any x86-64 CPU; raw throughput

    • FPNGE — AVX2, used automatically on capable CPUs; faster than FPNG

    • ZPNG — zlib-ng backed, NEON/AVX2 accelerated; best file size for screen content

  • Runtime hasAVX2() CPUID probe — no AVX2 library is loaded on unsupported hardware

  • FFM for JDK22+, JNA for older JDKs

  • Encodes BufferedImage directly — 3-channel (RGB) and 4-channel (RGBA)

  • Handles Java’s native TYPE_3BYTE_BGR / TYPE_4BYTE_ABGR channel order in C via SIMD byte shuffles (NEON on ARM64, SSE/AVX2 on x86)

  • Interleaved Adler32 checksum — no redundant full-image pass (FPNG/FPNGE)

  • PCLMUL-accelerated CRC32

  • Supports Java 8, Java 11, Java 17, Java 21, and Java 23

  • Platforms: Linux x86-64 / ARM64, macOS x86-64 / ARM64 (Apple Silicon), Windows x86 / x86-64

  • All binaries built and tested natively on each target platform via GitHub Runners

Benchmarks

Run the JMH benchmarks with:

./gradlew jmh

Results are written to benchmark/build/results/jmh/results.json.

Speed

JMH PNG Encoder Benchmark Report

PNG Encoder Benchmark Report

Generated by Manticore Projects · JMH ms/op · lower is better

3 ch text_test.png

Encoder Score (ms/op) Error vs Winner
FPNGE (Java 23 FFM) 2.291 ±NaN baseline
FPNGE (Java 23 FFM) 2.591 ±NaN +13.1%
FPNGE (JNI) 2.657 ±NaN +16.0%
FPNGE (JNI) 2.972 ±NaN +29.8%
FPNGE (Java 23 FFM) 3.350 ±NaN +46.2%
FPNGE (JNI) 3.763 ±NaN +64.3%
FPNGE (Java 23 FFM) 4.625 ±NaN +101.9%
FPNG Encoder (Java 23) 4.695 ±NaN +104.9%
FPNGE (JNI) 5.025 ±NaN +119.4%
FPNGE (Java 23 FFM) 5.104 ±NaN +122.8%
ZPNG23Benchmark 5.517 ±NaN +140.8%
FPNGE (JNI) 5.531 ±NaN +141.4%
FPNG Encoder (Java 23) 5.871 ±NaN +156.3%
FPNG Encoder (Java 23) 5.902 ±NaN +157.7%
PNGEncoder (fastest) 6.984 ±NaN +204.9%
ZPNG23Benchmark 7.307 ±NaN +219.0%
FPNG Encoder (JNI) 7.383 ±NaN +222.3%
FPNG Encoder (Java 23) 7.792 ±NaN +240.1%
FPNG Encoder (Java 23) 7.914 ±NaN +245.5%
PNGEncoder (fastest) 8.323 ±NaN +263.3%
FPNG Encoder (JNI) 8.579 ±NaN +274.5%
FPNG Encoder (JNI) 8.591 ±NaN +275.0%
FPNG Encoder (JNI) 9.835 ±NaN +329.4%
FPNG Encoder (JNI) 10.120 ±NaN +341.8%
PNGEncoder (fastest) 10.698 ±NaN +367.0%
PNGEncoder (fastest) 12.615 ±NaN +450.7%
PNGEncoder (fastest) 15.023 ±NaN +555.8%
ZPNG23Benchmark 22.746 ±NaN +892.9%
ZPNG23Benchmark 23.545 ±NaN +927.8%
ZPNG23Benchmark 25.026 ±NaN +992.5%
ImageIO 36.859 ±NaN +1509.0%
ImageIO 36.895 ±NaN +1510.6%
ImageIO 36.928 ±NaN +1512.1%
ImageIO 38.221 ±NaN +1568.5%
ImageIO 38.263 ±NaN +1570.4%
ObjectPlanet PNG 53.660 ±NaN +2242.5%
ObjectPlanet PNG 55.038 ±NaN +2302.6%
ObjectPlanet PNG 57.271 ±NaN +2400.1%
PNGEncoder 57.828 ±NaN +2424.4%
ObjectPlanet PNG 59.245 ±NaN +2486.3%
ObjectPlanet PNG 61.444 ±NaN +2582.3%
PNGEncoder 61.974 ±NaN +2605.4%
PNGEncoder 62.756 ±NaN +2639.6%
PNGEncoder 66.641 ±NaN +2809.2%
PNGEncoder 69.236 ±NaN +2922.4%
Manticore Projects © 2026 · JMH benchmark report · JDK 23 · Serial GC · 1×3 fork/iteration

Efficiency

JMH PNG Encoder Pareto Report

PNG Encoder Pareto Report

Generated by Manticore Projects · encode time vs. file size · lower-left is better

3 ch text_test.png

Overall best ZPNG23Benchmark at level 2 — 7.31 ms, 187.0 KB
overall winner
per-encoder knee
pareto-optimal
dominated

FPNG Encoder (JNI)

Lvl Status Time (ms) Size (KB) Ratio
1 dominated 10.12 ±NaN 339.3 4.2%
2 dominated 8.58 ±NaN 8155.5 100.0%
3 dominated 8.59 ±NaN 8155.5 100.0%
4 PARETO 7.38 ±NaN 668.2 8.2%
5 PARETO 9.84 ±NaN 339.3 4.2%

FPNG Encoder (Java 23)

Lvl Status Time (ms) Size (KB) Ratio
1 PARETO 7.79 ±NaN 339.3 4.2%
2 dominated 5.90 ±NaN 8155.5 100.0%
3 dominated 5.87 ±NaN 8155.5 100.0%
4 PARETO 4.69 ±NaN 668.2 8.2%
5 dominated 7.91 ±NaN 339.3 4.2%

FPNGE (JNI)

Lvl Status Time (ms) Size (KB) Ratio
1 PARETO 2.66 ±NaN 741.6 94.7%
2 dominated 2.97 ±NaN 783.3 100.0%
3 PARETO 3.76 ±NaN 685.4 87.5%
4 KNEE 5.02 ±NaN 684.7 87.4%
5 PARETO 5.53 ±NaN 525.9 67.1%

FPNGE (Java 23 FFM)

Lvl Status Time (ms) Size (KB) Ratio
1 PARETO 2.29 ±NaN 736.1 94.0%
2 dominated 2.59 ±NaN 783.3 100.0%
3 KNEE 3.35 ±NaN 679.9 86.8%
4 dominated 4.63 ±NaN 684.7 87.4%
5 PARETO 5.10 ±NaN 525.9 67.1%

ImageIO

Lvl Status Time (ms) Size (KB) Ratio
1 dominated 38.26 ±NaN 152.1 100.0%
2 PARETO 36.86 ±NaN 152.1 100.0%
3 dominated 38.22 ±NaN 152.1 100.0%
4 dominated 36.89 ±NaN 152.1 100.0%
5 dominated 36.93 ±NaN 152.1 100.0%

ObjectPlanet PNG

Lvl Status Time (ms) Size (KB) Ratio
1 PARETO 53.66 ±NaN 336.4 100.0%
2 KNEE 55.04 ±NaN 187.0 55.6%
3 PARETO 57.27 ±NaN 169.0 50.2%
4 PARETO 59.25 ±NaN 152.0 45.2%
5 PARETO 61.44 ±NaN 144.6 43.0%

PNGEncoder

Lvl Status Time (ms) Size (KB) Ratio
1 dominated 61.97 ±NaN 336.5 100.0%
1 PARETO 6.98 ±NaN 336.5 100.0%
2 dominated 62.76 ±NaN 187.1 55.6%
2 KNEE 8.32 ±NaN 187.1 55.6%
3 dominated 57.83 ±NaN 169.1 50.2%
3 PARETO 10.70 ±NaN 169.1 50.2%
4 dominated 66.64 ±NaN 152.1 45.2%
4 PARETO 12.62 ±NaN 152.1 45.2%
5 dominated 69.24 ±NaN 144.6 43.0%
5 PARETO 15.02 ±NaN 144.6 43.0%

ZPNG23Benchmark

Lvl Status Time (ms) Size (KB) Ratio
1 PARETO 5.52 ±NaN 338.8 100.0%
2 WINNER 7.31 ±NaN 187.0 55.2%
3 PARETO 22.75 ±NaN 168.2 49.6%
4 PARETO 23.55 ±NaN 151.7 44.8%
5 PARETO 25.03 ±NaN 144.2 42.6%
Manticore Projects © 2026 · Pareto frontier marks non-dominated (encoder, level) combinations · knee = perpendicular-distance maximum on normalized axes