I have written about using lossless optimisations techniques to reduce the size of images before, but I recently learned of a few other tools to further reduce the size of PNG images.

Basic optimisation

While you could use Smush.it to manually optimise your images, if you want a single Open Source tool you can use in your scripts, optipng is the most effective one:

optipng -o9 image.png

Removing unnecessary chunks

While not as effective as optipng in its basic optimisation mode, pngcrush can be used remove unnecessary chunks from PNG files:

pngcrush -q -rem gAMA -rem alla -rem text image.png image.crushed.png

Depending on the software used to produce the original PNG file, this can yield significant savings so I usually start with this.

Reducing the colour palette

When optimising images uploaded by users, it's not possible to know whether or not the palette size can be reduced without too much quality degradation. On the other hand, if you are optimising your own images, it might be worth trying this lossy optimisation technique.

For example, this image went from 7.2 kB to 5.2 kB after running it through pngnq:

pngnq -f -n 32 -s 3 image.png

Re-compressing final image

Most PNG writers use zlib to compress the final output but it turns out that there are better algorithms to do this.

Using AdvanceCOMP I was able to bring the same image as above from 5.1kB to 4.6kB:

advpng -z -4 image.png

When the source image is an SVG

Another thing I noticed while optimising PNG files is that rendering a PNG of the right size straight from an SVG file produces a smaller result than exporting a large PNG from that same SVG and then resizing the PNG to smaller sizes.

Here's how you can use Inkscape to generate an 80x80 PNG:

inkscape --without-gui --export-width=80 --export-height=80 --export-png=80.png image.svg

Other options for generating PNG from SVG are:

rsvg -w 64 -h 64 icon.svg icon.png

convert -geometry 64x64 -depth 8 -background none icon.svg icon.png

I'm curious as to which is best. Of course, best of all (for packaging) would be to be able to just install the SVG file and have PNG and XPM files generated automatically, in the "best" way whatever that might be, by dpkg triggers.

Comment by Barak A. Pearlmutter

Some more png chunks can generally be removed (with caveats such as not removing copyright if it's not your image…)

I use:

pngcrush -q \
-rem alla -rem gAMA -rem cHRM -rem iCCP \
-rem sRGB -rem tRNS -rem bKGD -rem pHYs \
-rem sBIT -rem tPLT -rem hIST -rem tIME \
-rem tEXT -rem iTXt -rem zTXt -rem vpAg \
in.png out.png

Reducing the number of colors to <= 256 distinct colors allows encoding of the image with a palette rather than RGB (often smaller except for small images).

Image magick is also handy. It can reduce the depth (number of bits per R, G, B, alpha). It's lossy but can be acceptable. Encoding can then be more efficient after rerunning pngcruh + optipng. For example, to reduce the depth to 4 bits per RGB:

$ convert -depth 4 in.png out.png

Command 'pngcheck -v in.png' is also handy to see what png chunks are present in an image.

Comment by dominiko