Log entry (14/10/2023)
Since my arrival on Planet Zopfli, I have been beholden to a tepidly persuasive contract: Marginally improved output in exchange for lengthy processing times, each yield requiring up to four samples of differing origins. Thankfully, this dull endeavour was disrupted by a notification which painted itself on my terminal:
OxiPNG v9.0.0 firmware now available. Restart mining subsystem to apply updates.
Important update
OxiPNG v9.0.0 has been released, which naturally means some of the results from before have changed because of new optimisations and updated dependencies, here’s hoping on some improvements!
Please eliminate the variants.
Please eliminate the variants.
COME ON! COME ON! COME-
Data analysis
Typical case
Ah, screw it, you know the drill by now.
The interesting stuff
Okay, we saved one byte for the Zopfli variants, same story though.
With the OxiPNG update, a lot of the size differences between the variants have been flattened out, however, like in this case, the results can be worse compared to the previous release (e.g. “OxiPNG-ZF” output size from the previous release: 2256 bytes, which is five bytes smaller).
Of course, “CWebP” was more effective here anyways, so the actual smallest encoding didn’t increase at all, I just thought this point was noteworthy.
And as you can see by the ‘Invert.png’ results, the PNGQuant combos are, annoyingly, still effective. Sure, “CWebP” absolutely destroys the OxiPNG variants here, but if we encounter a ‘series-deciphering_hugo.png’-esque result, we’ll need to try all the OxiPNG variants regardless to ensure the smallest encoding is found.
Strangely, this specific pre-release build of OxiPNG achieved an even smaller output at 1500130 bytes (Oxi-ZF-Quant variant).
…Why? Well now, I think I have an answer.
Indexed colours
The pre-release build and the “PNGQuant” variants share a difficult problem which is (most likely) the cause of the output size variance: Colour palette optimisation.
Each index in an indexed colour palette consists of a single byte, however, not every byte is equally compressible, 00000010 is a lot simpler than 01110011 (and that’s not even considering when the bytes are chained together), therefore, the frequency of each colour and thus its index drastically affects the image data’s compressibility.
Unfortunately, palette optimisation isn’t trivial to solve nor implement, although algorithms focused on this problem do exist as found by Kornel (the creator of pngquant and Gifski).
Addendum
OxiPNG v9.1.0 added a palette sorting method which has improved the situation, however, do note that this method is not guaranteed to find the smallest result possible; it’s not a brute-force algorithm.
Heuristics
In hopes of reducing the amount of processing time needed per image, I’m proposing a new heuristic for avoiding the OxiPNG variants in most cases:
- Typically, the normal OxiPNG output is more than 10% larger than the “CWebP” output.
- And usually, the OxiPNG variants are less than 10% smaller than the normal OxiPNG output.
- Therefore, if the OxiPNG output isn’t within 110% of the “CWebP” output, you can skip running the OxiPNG variants as it’s unlikely any of them would find a smaller image encoding.
Obviously, these percentages are based solely on my image set, which is only about twenty images and it’s biased towards my own pixel art, so to create a more generic heuristic, I’ll need to expand my dataset. Until then…