How to generate smaller PNG files in Java

As you may already know, PNG is a lossless image format which has comparatively larger file sizes when compared to JPEG. But often PNG is more popular for example because it also has Alpha support (you can add custom alpha support in JPEGs but it needs tweaks in JFIF and APP segments). So can we improve on the size of PNG files?

The article explains how. Instead of using 24 or 32 bits per pixel, we will use 8 bits per pixel to map each pixel to a color in a 256 color palette (Note: Each color in the palette contains 24 or 32 bits of information). This gives us much smaller PNG files.

I provide an overview of how to convert RGB/ARGB images to 8 bit palette images by reducing the total number of colors to 256 if you are looking to implement this yourself. If you just want to generate smaller PNG images now, it shows how you can use this feature in your own Java code with our JDeli Java Image library.

Why do we need Quantisation?

If an image contains 256 colours or less, then 256 color palette mapping produces lossless results; But if an image contains a large number of colors then the color palette needs to be chosen in a way that optimizes for colours that are most common in order to generate an outcome that is visually acceptable. This is where quantisation plays a major role.

Algorithms such as Median cut, Neural Quantisation, Octree, Xiaolin wu, etc generate aesthetically pleasing color palettes; However each of above algorithms have pros and cons as far as memory and speed are concerned.

The images below exemplifies the quantization (the image on the left is original and the one on the right is quantised (using Wu’s algorithm)

lenalenaWu

(606KB vs 185KB)

Is Quantisation enough for image compression ?

Quantisation often generates aesthetically unpleasant results for images that contain shadings or highly interpolated colors; see the example shown below (the image on the left is original and the one on the right is quantised);

lattice1435564421101

(709KB vs 29KB)

Add Dithering to produce high quality, smaller images 

Dithering is a technique is used to approximate, diffuse and adjust the pixel mapping locations in order to provide aesthetically pleasing output.

Here is an example of the above image after quantisation and dithering.

1435565254346

(98KB)

Using in Java

Unfortunately, ImageIO does not support Quantisation, although you can use several non-Java libraries such as PngQuant to post-process PNGs created with ImageIO.

In our JDeli Java Image library, we have been adding functionality we need which is not available in Java. So you can now Quantise a PNG in JDeli with simple java code as shown below:

//Compress Image
PngCompressor.compress(inputPngFile, outputPngFile);

PngCompressor.compress(inputFile,outputFile);

Please Note: JDeli utilizes Wu’s color quantisation with Floyd-Steinberg dithering.

Here is an example with transparency:

ghostOriginal   ghostQuant

(137KB vs 23KB)

Hopefully you have found this useful.

We have also created a useful how to series on how to read and write various Image formats.

If you’re a first-time reader, or simply want to be notified when we post new articles and updates, you can keep up to date by social media (Twitter, Facebook and Google+) or the Blog RSS.

Related Posts:

The following two tabs change content below.

suda

Java EE developer at IDRSolutions
Suda is the Senior Java EE Developer at IDR Solutions, and specialises in XFA, Fonts, True-Type Fonts, application servers and conversions. He is a keen science-fiction fan in his spare time.
suda

About suda

Suda is the Senior Java EE Developer at IDR Solutions, and specialises in XFA, Fonts, True-Type Fonts, application servers and conversions. He is a keen science-fiction fan in his spare time.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>