Java Compression Library

Compress and decompress image data in pure Java. Supports Flate, LZW, DCT, Brotli, CCITT, JBIG2, JPX, RLE and more with no native dependencies.

JDeli provides 10 filters for compressing & decompressing image data in pure Java (Java 17+) with no native or third-party dependencies. It handles Ascii85, AsciiHex, Brotli, CCITT, DCT, Flate, JBIG2, JPX, LZW, and RLE through a single static API.

Input can be byte arrays directly, or InputStreams and OutputStreams for larger data. See the full filter documentation for the complete API reference.

Compress data in Java with two lines of code

These examples use Flate (Deflate), the most commonly used lossless compression filter for image streams.

// Compress a byte array using Flate (Deflate)
FlateFilterOptions options = new FlateFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
byte[] compressed = JDeli.filter(rawData, options);

// Decompress back to the original data
FlateFilterOptions decompressOptions = new FlateFilterOptions();
decompressOptions.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] original = JDeli.filter(compressed, decompressOptions);
// Compress an InputStream to an OutputStream
FlateFilterOptions options = new FlateFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
JDeli.filter(inputStream, options, outputStream);

// Decompress an InputStream to an OutputStream
FlateFilterOptions decompressOptions = new FlateFilterOptions();
decompressOptions.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, decompressOptions, outputStream);

How to compress image data in Java

  1. Add the JDeli JAR to your project classpath, or add it as a Maven or Gradle dependency.
  2. Choose the compression filter that matches your data type. Flate works for most use cases; LZW is common for TIFF and GIF data; DCT handles JPEG streams. See the filter comparison table below for the full list.
  3. Create the corresponding FilterOptions object and call setMode(FilterOptions.FilterMode.COMPRESS).
  4. Pass your data and options to JDeli.filter(). Use the byte[] overload for small data or the InputStream/OutputStream overload for large files.
  5. To decompress, change the mode to FilterOptions.FilterMode.DECOMPRESS and call the same method.

For PNG-specific compression (reducing PNG file sizes without quality loss), see How to compress PNG files with PngCompressor.

All compression and decompression filters

// Compress byte[]
ASCII85FilterOptions options = new ASCII85FilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
byte[] compressed = JDeli.filter(rawData, options);

// Decompress byte[]
ASCII85FilterOptions options = new ASCII85FilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Compress InputStream
ASCII85FilterOptions options = new ASCII85FilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
JDeli.filter(inputStream, options, outputStream);

// Decompress InputStream
ASCII85FilterOptions options = new ASCII85FilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Compress byte[]
ASCIIHexFilterOptions options = new ASCIIHexFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
byte[] compressed = JDeli.filter(rawData, options);

// Decompress byte[]
ASCIIHexFilterOptions options = new ASCIIHexFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Compress InputStream
ASCIIHexFilterOptions options = new ASCIIHexFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
JDeli.filter(inputStream, options, outputStream);

// Decompress InputStream
ASCIIHexFilterOptions options = new ASCIIHexFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Decompress byte[]
BrotliFilterOptions options = new BrotliFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Decompress InputStream
BrotliFilterOptions options = new BrotliFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Decompress byte[]
CCITTFilterOptions options = new CCITTFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Decompress InputStream
CCITTFilterOptions options = new CCITTFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Decompress byte[]
DCTFilterOptions options = new DCTFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Decompress InputStream
DCTFilterOptions options = new DCTFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Compress byte[]
FlateFilterOptions options = new FlateFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
byte[] compressed = JDeli.filter(rawData, options);

// Decompress byte[]
FlateFilterOptions options = new FlateFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Compress InputStream
FlateFilterOptions options = new FlateFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
JDeli.filter(inputStream, options, outputStream);

// Decompress InputStream
FlateFilterOptions options = new FlateFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Decompress byte[]
JBIG2FilterOptions options = new JBIG2FilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Decompress InputStream
JBIG2FilterOptions options = new JBIG2FilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Decompress byte[]
JPXFilterOptions options = new JPXFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Decompress InputStream
JPXFilterOptions options = new JPXFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Compress byte[]
LZWFilterOptions options = new LZWFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
byte[] compressed = JDeli.filter(rawData, options);

// Decompress byte[]
LZWFilterOptions options = new LZWFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Compress InputStream
LZWFilterOptions options = new LZWFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
JDeli.filter(inputStream, options, outputStream);

// Decompress InputStream
LZWFilterOptions options = new LZWFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);
// Compress byte[]
RLEFilterOptions options = new RLEFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
byte[] compressed = JDeli.filter(rawData, options);

// Decompress byte[]
RLEFilterOptions options = new RLEFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
byte[] decompressed = JDeli.filter(rawData, options);

// Compress InputStream
RLEFilterOptions options = new RLEFilterOptions();
options.setMode(FilterOptions.FilterMode.COMPRESS);
JDeli.filter(inputStream, options, outputStream);

// Decompress InputStream
RLEFilterOptions options = new RLEFilterOptions();
options.setMode(FilterOptions.FilterMode.DECOMPRESS);
JDeli.filter(inputStream, options, outputStream);

Which compression filter should you use?

JDeli supports 10 filters. The right choice depends on your image format and whether you need lossless or lossy compression.

Filter Best for Modes Learn more
Ascii85 Encodes binary image data as printable ASCII text Compress, Decompress Tutorial
AsciiHex Encodes binary image data as hexadecimal text Compress, Decompress Tutorial
Brotli High-ratio lossless compression Decompress Tutorial
CCITT Bilevel (black and white) fax-style image compression Decompress Tutorial
DCT Lossy compression for JPEG image data Decompress Tutorial
Flate General-purpose lossless compression for image streams Compress, Decompress Tutorial
JBIG2 High-ratio compression for scanned bilevel document images Decompress Tutorial
JPX JPEG 2000 wavelet-based image compression Decompress Tutorial
LZW Lossless compression used in TIFF and GIF image formats Compress, Decompress Tutorial
RLE Run-length encoding for data with long repeated byte sequences Compress, Decompress Tutorial

"I was looking specifically for a Java-based compression technique, I'm happy because it's taking up less space on the server."

- Kevin Lauder (ISC Engineering Senior Manager)

Common issues when compressing data in Java

Compressing already-compressed data increases size. Applying Flate to data that is already Flate-compressed will not reduce it further. The framing overhead usually makes the output slightly larger than the input. Compress once.

DCT is lossy. Each compress-decompress cycle with DCT (JPEG) degrades image quality. If you need to round-trip image data without loss, use Flate or LZW instead.

CCITT and JBIG2 expect bilevel images. These filters are designed for 1-bit black-and-white image data. Passing colour or grayscale data will produce incorrect output. Check your image colour model before choosing a filter.

Use streams for large data. The byte[] overload of JDeli.filter() loads everything into heap memory. For large image streams, use the InputStream/OutputStream version to avoid OutOfMemoryError.

How do you achieve such good performance? So many companies attempting writing image codecs in Java end up in far slower performance or claim better performance requires native code.

- David E. (Lead developer and founder of jAlbum)

Frequently Asked Questions

What compression formats does JDeli support?

JDeli supports 10 filters: Ascii85, AsciiHex, Brotli, CCITT, DCT, Flate, JBIG2, JPX, LZW, and RLE. See the full filter list.

Does JDeli require native libraries or DLLs?

No. All 10 compression filters (Brotli, LZW, Flate, CCITT, and others) are implemented in pure Java with no JNI and no native dependencies. It runs on any platform with Java 17 or later.

How does JDeli's performance compare to alternatives?

JDeli's encoders and decoders are up to 3x faster than ImageIO and other Java image libraries in independent benchmarks. See the performance comparison for detailed numbers.

Does JDeli make network calls when compressing or decompressing data?

No. JDeli compresses and decompresses data entirely within your JVM process. It makes no network calls, has no licensing server, and sends no telemetry. Suitable for air-gapped environments and compliance-restricted deployments.

We replaced all our various image processing code with JDeli, which allowed us to smoothly migrate to Java 11. The support from IDR solutions is just great. Whenever we came across a strange image from our customers which JDeli couldn't read properly, IDR fixed it in less than a day.

- Developer in SME Financial Services Company

JDeli vs. Open-Source Alternatives

Most developers try open source first — that's the right call. Here's what they typically find.

No Pure Java AVIF or HEIC Support

Most open source Java image libraries don't support AVIF or HEIC at all. The ones that do are JNI wrappers around native C libraries — which means native installs on your server, JVM crash risk, and a build that can no longer ship as a single JAR.

Unmaintained Libraries Break on Upgrade

Oracle dropped JPEG 2000 from Java. JAI is unmaintained. When you upgrade your JDK, these libraries stop working and nobody fixes them. Security scans flag them as unsupported software before there's even a CVE.

No Support in Production

When a customer-uploaded image exposes a bug in an open source library, you're filing a GitHub issue and hoping the maintainer responds. JDeli customers get same-day fixes from the engineers who wrote the code.

JDeli is written from scratch in pure Java — no native code, no JNI, no external dependencies. One JAR covers AVIF, HEIC, TIFF, WebP, JPEG 2000, and 15+ formats. The ImageIO plugin means your existing code needs no changes.

Actively maintained with regular releases and fast, named support. Performance comparisons and security documentation available.

Trusted by Companies around the World

Abacus logo
Citi logo
Clearsense logo
Honeywell logo
Los Alamos National Lab logo
Mercedes-Benz Bank logo

Extend Java capabilities

(works with your existing code!)

1.

Adds new image formats (AVIF, HEIC, JPEG XL, WEBP)

2.

Improves support for common file formats (JPEG, JPEG2000, PNG, TIFF)

3.

Up to 3X improved performance (see comparison)

Try JDeli for Free