The following 87 byte PNG (reproduced here in hex) was produced by using GIMP. It's a single-color 1x11 pixel image with an alpha channel that makes it appear as a gradient when it is displayed against a background that has a different color. Can anyone think of a way of reducing the size of the file even further? I was unable to do that with PNGOUT.
You can run OPTIPNG or PNGCRUSH on your file to turn it into 85 bytes. This image compresses best with "Fixed Huffman" because it is so small. PNGOUT only uses dynamic Huffman - that's why it can't compete. If I enabled the "Fixed Huffman" strategy, PNGOUT would also give an 85 byte file. In fact, I believe 85 bytes is the smallest possible file size for this particular image. : )
The Gimp at
Thanks a lot, Ken!
Martin at
I have many small PNGs (e. g. 80x15 pixels with only a few colors). Here's an example: http://img53.exs.cx/img53/2935/sendofix7ba.png Could those images be compressed further with the "fixed Huffman" strategy you mentioned? (I tried PNGcrush and OptiPNG with the image above, they didn't lower the filesize, but maybe with other images like that?) And if so, would you mind implementing such an option in PNGOUT? ^^
Awesoken at
Actually, your 80x15 file compresses best with dynamic Huffman. I was able to knock off 1 byte using my randomized initial Huffman table hack (which is not in the public version) and running a few hundred trials with it:
I could implement options for fixed Huffman (aka: RFC-1951, BTYPE=01), but I don't think my algorithm would have any advantage over the other programs (advpng, advdef, optipng) in this mode. When I compress PNG files, I actually use a combination of all these programs until satisfied. Sure, implementing this in PNGOUT would make for less typing... but fixing it is not a priority for me right now.
counting_pine at
I managed to knock two bytes off the original image by rearranging the palette, giving the coveted palette index 0 to the grey border.
I don't know if any more can be knocked off with Ken's publicly unavailable compression methods.
By the way, a lot of programs (including bmp2png and OptiPNG) use the zLib Deflate algorithm, which automatically attempts Fixed Huffman compression. It doesn't usually get the best results, only when the file is "very, very small", or "quite small and very compressible".
For example, Pinstripe.bmp, which comes with Win9x and is just a 32x32 image of vertical lines, compresses better with Fixed Huffman.
(FYI Fixed Huffman can get sendofix.png down to 193 bytes, which is pretty close, but it's still a reasonably big margin, considering the small file size)
I think, of all the main PNG optimisers, OptiPNG is the only one that tries Fixed Huffman. AdvDef and AdvPNG use the 7-zip Deflate algorithm, which doesn't seem to try it, and obviously PNGOut doesn't at present.
Note that, although OptiPNG tries Fixed Huffman, its algorithm doesn't necessarily produce Fixed Huffman blocks of optimal size. This is probably only something that can be achieved with something like PNGOut's algorithm.
Martin at
I don't really know what fixed and dynamic Huffman actually does, I just wondered if fixed Huffman could produce better results in general with small images. In any case, I'm happy with the compression rates PNGOUT already achieves :)
BTW, here's some PHP I wrote to transform hexcode into (PNG) images:
I don't really know what fixed and dynamic Huffman actually does, I just wondered if fixed Huffman could produce better results in general with small images
The difference between "Fixed Huffman" and "Dynamic Huffman" is that a "Fixed Huffman" block uses fixed Huffman codes, predefined by the specification, and a "Dynamic Huffman" block makes its own Huffman codes, and can use them to compress the data better.
So, basically, "Dynamic Huffman" blocks normally allow better compression, but they need an overhead to include the Huffman codes. With small files, the Huffman codes take up too much room, so "Fixed Huffman" is smaller.
Awesoken said
Nice work! Was that an intelligent guess or just trial & error?
Thanks :) It was a semi-intelligent guess based on thinking about the invisible filter byte at the beginning of each row (which happens to be always zero here).
The border colour is the only one that's adjacent to the row filter byte, so I tried making it zero as well. The consequence is a nice run of zeros at the start and end of the image data:)