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)
(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);
(726KB 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.
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);
Please Note: JDeli utilizes Wu’s color quantisation with Floyd-Steinberg dithering.
This article is part of our series on reading and writing image files in Java.
Read and write images in Java with one line of code
Read an Image with
BufferedImage image = JDeli.read(streamOrFile);
and write an Image with
JDeli.write(myBufferedImage, OutputFormat.HEIC, outputStreamOrFile)