overviewer/Minecraft-Overviewer — pull request #1074 by CounterPillow (2014-03-04 00:05:18+00:00)
Title: Rewrote image optimisation stuff.

I've noticed that the image optimization option ``optimizeimg`` in Overviewer was pretty broken. Here's some of the brokenness:

* The documentation said that ``1`` is pngcrush, ``2`` is advdef, ``3`` is pngcrush + advdef, but in reality ``2`` would do pngcrush + advdev -z2, and ``3`` would do pngcrush + advdev -z4 (with no -i specified, lol)
*Surprisingly though, the docstring in tileset.py was correct.*

* However, this was irrelevant anyways, because the validator did ``return bool(opt)``, so only level 1 could ever be used.

* Overloading integers with different meanings is silly.

Now, it's a list of classobjs which all inherit from Optimizer instead! This means we can chain multiple Optimizers together, and have some fun.

New Classes in optimizeimages.py
===========================

Optimizer
------------

This is the base class of which all Optimizers must inherit in some way to be seen as a valid Optimizer.

NonAtomicOptimizer
-------------------------

Optimizers which can't write to the same file they've read from (e.g. pngcrush) should derive from this, which manages temporary file things.

PNGOptimizer
------------------

All optimizers which can handle PNG images should inherit from this, or otherwise they'll be ignored for PNG images.

JPEGOptimizer
-------------------

All optimizers which can handle JPEG images should inherit from this, or otherwise they'll be ignored for JPEG images.

pngnq
--------

Uses the pngnq tool to quantize images down to indexed PNG8 images! PIL stupidity still applies, because not only does it fail to write correct PNG8 images with transparency, it also fails to read them, which means that all levels except for the most zoomed in one have transparency replaced by the colour black. This is noted in the docs.

optipng
---------

Uses the optipng tool to do various lossless optimisations. This should be used by most people who are interested in image file optimisations.

pngcrush
------------

Just for lols and backwards compatibility. It's slower and not as good as optipng, which has also been noted in the docs.

Questions and Answers
===================

**Q: But I liked my integers! Why the change?**

**A:** Because it was broken. Furthermore, this allows for more flexibility and extensibility. If you want the old behaviour back (for all values greater or equal 1), just use ``"optimizeimg":[pngcrush()]``, but you'll probably want to use optipng.

**Q: Did you test this?**

**A:** Kinda? I was able to run pngnq with optipng chained together, as well as pngcrush alone. I'd be happy to have it tested more thoroughly though, especially to see what happens when we throw integers at ``optimizeimg``.

**Q: Does this even do anything for file compression?**

**A:** I was able to (lossily) compress a ~740,000 bytes map down to ~250,000 bytes with ``"optimizeimg":[pngnq(sampling=1), optipng(olevel=3)]``. I think the numbers speak for themselves.

**Q: Why isn't advdef back?**

**A:** Because I'm lazy, and because I haven't seen a case where advdef was actually beneficial. In a test I did (be warned: only on a single image), advpng actually made the image larger than the source, while all other optimisation utilities made it smaller. Even pngcrush.

**Q: Are there other optimisation thingies to add?**

**A:** The closed source "pngout" would probably be a candidate, because it is the most efficient lossless PNG optimiser out there.