OVERHEAD

Captain’s log

BYTE WARS

Log entry (22/09/2023)

The Oculorum nebula has proven to be a strange and unintuitive place. The imagery around me appears to shift and distort in volume, and yet, all attempts to capture this sensation yield nothing of substance; it is though the very particles themselves are sizing me up, ready to-

Okay, that’s enough, let’s get into the data.

Data analysis

To compare the different techniques and tools, I gathered nineteen images of varying colour quantities, image dimensions, and overall complexity, ranging from simple pixel art, to 4K widescreen images.

Showing all the results here would be meaningless, since they tended to be similar, so instead, I’m going to be analysing a useful subset of the images. Here’s a basic rundown of how these results were collected:

  1. The original image is fed into pngquant, such that if the image can’t be optimised without changing it visually, the input is given as the output (and hence share the same size).
  2. Concurrently, the original image is fed into oxipng at max settings, and to cwebp in lossless mode.
  3. If pngquant doesn’t duplicate the input image, then the output is fed into oxipng (which is the “Oxi-Quant” entry). Otherwise, the output of oxipng is copied.

Or more precisely, the commands were:

  • pngquant --quality 100-100 --speed 1 --strip “$original_image” --output “$path_to_quant_output”
  • oxipng --opt max --strip all “$original_image” --out “$path_to_oxi_output” (same options for “Oxi-Quant”)
    • Link to OxiPNG GitHub page.
    • OxiPNG is a multithreaded version of the previously covered OptiPNG tool, which is not only substantially faster, but generates even more compact image encodings.
  • cwebp -z 9 -mt “$original_image” -o “$path_to_cwebp_output”

Lossless AVIF was excluded since, unlike WebP, it doesn’t have a separate encoding scheme for lossless mode, which gave it no chance of winning.

Typical case

For the vast majority of non-pixel-art images, the results looked like this:

Results for the ‘Commercial Break.png’ image, with the best-to-worst encoding order being: CWebP, OxiPNG or Oxi-Quant, then PNGQuant or Original.

Filename:		'Commercial Break.png'
Original Filesize:	3733779 bytes
PNGQuant Filesize:	3733779 bytes
OxiPNG Filesize:	3098589 bytes
Oxi-Quant Filesize:	3098589 bytes
CWebP Filesize:		2222816 bytes
Smallest encoding:	2222816 bytes, CWebP

And for pixel art images, the results looked like this:

Results for the ‘post-10k.png’ image, with the best-to-worst encoding order being: CWebP, OxiPNG or Oxi-Quant, PNGQuant, then Original.

Filename:		'post-10k.png'
Original Filesize:	7418 bytes
PNGQuant Filesize:	5540 bytes
OxiPNG Filesize:	5470 bytes
Oxi-Quant Filesize:	5470 bytes
CWebP Filesize:		5122 bytes
Smallest encoding:	5122 bytes, CWebP

So, pngquant helps a fair bit for pixel art, oxipng does even better in general and isn’t affected by the input being pngquant-optimised, and cwebp consistently takes the victory. Easy to understand and consistent-

Outliers

Other times though, you get results like this:

Results for the ‘series-deciphering_hugo.png’ image, with the best-to-worst encoding order being: OxiPNG or Oxi-Quant, CWebP, PNGQuant, then Original.

Filename:		'series-deciphering_hugo.png'
Original Filesize:	3819 bytes
PNGQuant Filesize:	1990 bytes
OxiPNG Filesize:	1885 bytes
Oxi-Quant Filesize:	1885 bytes
CWebP Filesize:		1918 bytes
Smallest encoding:	1885 bytes, OxiPNG

Unfortunately, cwebp isn’t the most effective tool for every possible case (damnit), however, using just oxipng will instead take the victory in those circumstances… right?

Results for the ’tag-css.png’ image, with the best-to-worst encoding order being: CWebP, Oxi-Quant, OxiPNG, PNGQuant, then Original.

Filename:		'tag-css.png'
Original Filesize:	4780 bytes
PNGQuant Filesize:	2474 bytes
OxiPNG Filesize:	2258 bytes
Oxi-Quant Filesize:	2256 bytes
CWebP Filesize:		2054 bytes
Smallest encoding:	2054 bytes, CWebP

Yeah, sure, or pngquant magically does something that oxipng doesn’t, causing the combo to be more effective than only using oxipng, because that makes sense. Well, then I guess always using both is the right-

Results for the ‘Hypercubes.png’ image, with the best-to-worst encoding order being: CWebP, OxiPNG, Oxi-Quant, Original, then PNGQuant.

Filename:		'Hypercubes.png'
Original Filesize:	605777 bytes
PNGQuant Filesize:	617188 bytes
OxiPNG Filesize:	577274 bytes
Oxi-Quant Filesize:	577729 bytes
CWebP Filesize:		544578 bytes
Smallest encoding:	544578 bytes, CWebP

Or not.

So, for the most optimal encoding, we would have to use all three tools plus the combo (except for the input-as-output case), and then pick the smallest output. Fun.

Additional notes

  • Although WebP lossless mode does preserve the RGBA values of every pixel from the original image (at least when using PNG as the input), it only supports 8-bit RBGA colours which makes it unsuitable for “losslessly” compressing HDR images.
  • Passing the “Oxi-Quant” images through cwebp had no effect on the output size compared to just using cwebp.
  • For gif2webp, and pixel art GIFs as the input, the output was substantially larger than what gifsicle or gif2apng could achieve, so they’re still the optimal tools.