Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PNG optimizer strategies from TruePNG #71

Open
4 of 7 tasks
ghuls opened this issue Jul 18, 2017 · 17 comments
Open
4 of 7 tasks

PNG optimizer strategies from TruePNG #71

ghuls opened this issue Jul 18, 2017 · 17 comments
Labels
I-Medium Issues that are breaking core functionality, but have a known workaround T-Compression Relates to improving the compression ratio of images T-Feature Requests for a new feature to be added T-Meta A collection of related issues

Comments

@ghuls
Copy link

ghuls commented Jul 18, 2017

TruePNG is a very good PNG optimizer, unfortunately it only runs on Windows (and under wine).

Some of the strategies is uses are described:

TruePNG is actually one of the most advanced PNG optimizer available. it does an exhaustive checks for reductions and should be able to transform image with more efficiency than other tools. those transformations are called "image reductions".

https://css-ig.net/articles/truepng.php

TruePNG binary:
http://x128.ho.ua/pngutils.html

Meta issues:

@shssoichiro shssoichiro added I-Medium Issues that are breaking core functionality, but have a known workaround T-Feature Requests for a new feature to be added T-Needs Tests labels Jul 18, 2017
@shssoichiro
Copy link
Owner

shssoichiro commented Jul 18, 2017

Oxipng already uses some of these techniques, but it looks like there are improvements to be gained here. I'll probably turn this into a meta issue and make sub-issues for each potential improvement, once I have time to go through the full list in detail.

@shssoichiro shssoichiro added the T-Meta A collection of related issues label Jul 18, 2017
@ghuls
Copy link
Author

ghuls commented Jul 19, 2017

Thanks.

At https://blog.codinghorror.com/zopfli-optimization-literally-free-bandwidth/ you can find an image that almost not optimized with oxipng (- 28 bytes), while TruePNG does much better (- 7016 bytes).

# Download image.
$ wget https://blog.codinghorror.com/content/images/2016/01/PBF274-Adam_2-0.png


# Compress original PNG with oxipng max setting (zlib):
$ oxipng -o 6 --zm 1-9 --strip all --out PBF274-Adam_2-0.oxipng_o6_zm1_9.png PBF274-Adam_2-0.png
Processing: PBF274-Adam_2-0.png
    800x1412 pixels, PNG format
    4x8 bits/pixel, RGBA
    IDAT size = 607025 bytes
    File size = 607110 bytes
Trying: 1944 combinations
    IDAT size = 607025 bytes (0 bytes decrease)
    file size = 607082 bytes (28 bytes = 0.00% decrease)
Output: PBF274-Adam_2-0.oxipng_o6_zm1_9.png


# Compress original PNG with oxipng max setting (zopfli):
$ oxipng -o 6 --zopfli --strip all --out PBF274-Adam_2-0.oxipng_o6_zopfli.png PBF274-Adam_2-0.png
Processing: PBF274-Adam_2-0.png
    800x1412 pixels, PNG format
    4x8 bits/pixel, RGBA
    IDAT size = 607025 bytes
    File size = 607110 bytes
Trying: 6 combinations
Found better combination:
    zc = 0  zm = 0  zs = 0  f = 0        581799 bytes
    IDAT size = 581799 bytes (25226 bytes decrease)
    file size = 581856 bytes (25254 bytes = 4.16% decrease)
Output: PBF274-Adam_2-0.oxipng_o6_zopfli.png


# Compress original PNG with TruePNG max setting:
$ wine TruePNG.exe PBF274-Adam_2-0.png /o max /out PBF274-Adam_2-0.truepng_max.png
TruePNG 0.6.2.2 : PNG Optimizer
by x128 (2010-2016)
x128@ua.fm

Input file: PBF274-Adam_2-0.png | 607110 bytes
Image: 800x1412 pixels | 8 bits/sample | RGB & Alpha
Delta filter: None
Chunks: gAMA

Output format: 8 bits/sample | RGB & Alpha
Chunks: gAMA

try...
IDAT=600021     file=600094     complete=100%

extra...

best:
zc:9    zm:8    zs:0    fs-:    f:0     IDAT=600021     file=600094


# Compress original PNG with zopflipng.
$ zopflipng  --iterations=10 PBF274-Adam_2-0.png PBF274-Adam_2-0.zopflipng_it10.png
Optimizing PBF274-Adam_2-0.png
Input size: 607110 (592K)
Result size: 581721 (568K). Percentage of original: 95.818%
Result is smaller


# Compress oxipng optimized file (with zlib) with zopflipng.
$ zopflipng  --iterations=10 PBF274-Adam_2-0.oxipng_o6_zm1_9.png PBF274-Adam_2-0.oxipng_o6_zm1_9.zopflipng_it10.png
Optimizing PBF274-Adam_2-0.oxipng_o6_zm1_9.png
Input size: 607082 (592K)
Result size: 581721 (568K). Percentage of original: 95.822%
Result is smaller

# Compress oxipng optimized file (with zopfli) with zopflipng.
$ zopflipng  --iterations=10 PBF274-Adam_2-0.oxipng_o6_zopfli.png PBF274-Adam_2-0.oxipng_o6_zopfli.zopflipng_it10.png
Optimizing PBF274-Adam_2-0.oxipng_o6_zopfli.png
Input size: 581856 (568K)
Result size: 581721 (568K). Percentage of original: 99.977%
Result is smaller


# Compress TruePNG optimized PNG with zopflipng.
$ zopflipng  --iterations=10 PBF274-Adam_2-0.truepng_max.png PBF274-Adam_2-0.truepng_max.zopflipng_it10.png
Optimizing PBF274-Adam_2-0.truepng_max.png
Input size: 600094 (586K)
Result size: 576829 (563K). Percentage of original: 96.123%
Result is smaller
# PNG filesizes:
$ stat --format '%n'$'\t''%s' PBF274-Adam_2-0.*png
PBF274-Adam_2-0.oxipng_o6_zm1_9.png     607082
PBF274-Adam_2-0.oxipng_o6_zm1_9.zopflipng_it10.png      581721
PBF274-Adam_2-0.oxipng_o6_zopfli.png    581856
PBF274-Adam_2-0.oxipng_o6_zopfli.zopflipng_it10.png     581721
PBF274-Adam_2-0.png     607110
PBF274-Adam_2-0.truepng_max.png 600094
PBF274-Adam_2-0.truepng_max.zopflipng_it10.png  576829
PBF274-Adam_2-0.zopflipng_it10.png      581721

@shssoichiro shssoichiro removed I-Medium Issues that are breaking core functionality, but have a known workaround T-Needs Tests labels Jul 21, 2017
@shssoichiro shssoichiro added the I-Medium Issues that are breaking core functionality, but have a known workaround label Oct 1, 2017
@shssoichiro shssoichiro added the T-Compression Relates to improving the compression ratio of images label Dec 12, 2018
@polarathene
Copy link

I might not have used TruePNG correctly, but on my input it's barely better than what I could get with oxipng... yet whatever compressor.io is doing, it's able to do huge reductions by comparison with image quality that looks the same.

oxipng -o 6 -i 0 --strip all svg_primitive.png = 60.4KiB
svg_primitive_oxipng

truepng -o4 -g0 -i0 -l -md remove all svg_primitive.png -out svg_primitive_truepng.png (both gave the same result, this was run on Arch Linux via the AUR package using WINE, no actual output image was created but the source file did change in size, so I assume it's working?)
truepng -fe -a1 -g0 -i0 -l -m=1 -cq c=256 -md remove all svg_primitive.png -out svg_primitive_truepng.png
Update: Seems to only accept one option input at a time... and any args(like -l or -cq has) seem ineffective :( Used /l(lossy) followed by /o4 which applied most of the above and a /cq, got 24.3KiB vs 59KiB initially getting.
svg_primitive_truepng

Compress.io Lossy setting, 29.2KiB
svg_primitive-compressor

Original at 62.7KiB
svg_primitive

Would be nice if there are any easy wins there for oxipng to offer a lossy output option too :)

@shssoichiro
Copy link
Owner

It looks like compressor.io uses pngquant behind the scenes, which uses quantization to reduce the number of colors needed to store a PNG image. It looks like this is represented in #76, but I must have checked off the wrong item in the list on this issue, because it's not implemented in oxipng yet.

@TPS
Copy link

TPS commented Jul 26, 2020

1 note: Be careful that you don't replicate TruePNG's faults (e.g., it can destroy certain 2-bit grayscale PNGs in a weird almost-interlaced fashion).

@javiergutierrezchamorro I've filed an extensive bug report re: this for FO.

@TPS
Copy link

TPS commented May 8, 2023

#502 completed №3 (#73) above.

@guls, @shssoichiro: Could that be checked off in the top post?

@ghuls
Copy link
Author

ghuls commented May 8, 2023

In the mean time I switched from TruePNG to pngquant + zopflipng for the specific type of images I had (final filesize was very close to TruePNG + zopflipng.

It seems like TruePNG is deprecated and replaced by https://css-ig.net/pingo (seems to have benchmarks with oxipng, which seem to give very similar results).

The following seems to generate much better images than in the past:

❯ oxipng -v -v  --strip=all -o max -Z --out /tmp/test.png test.png
Processing: test.png
    399x199 pixels, PNG format
    8-bit RGB, non-interlaced
    IDAT size = 15547 bytes
    File size = 18044 bytes
Eval: 8-bit Indexed (162 colors)  None       8283 bytes
Eval: 8-bit RGB                   None      >8283 bytes
Eval: 8-bit Indexed (162 colors)  Bigrams   >8292 bytes
Eval: 8-bit RGB                   Bigrams   >8292 bytes
Reducing image to 8-bit Indexed (162 colors), non-interlaced
Trying: 10 filters
    zc = 0  f = Sub       7936 bytes
    zc = 0  f = Average  >11763 bytes
    zc = 0  f = None      6510 bytes
    zc = 0  f = MinSum   >8756 bytes
    zc = 0  f = Brute    >7439 bytes
    zc = 0  f = Paeth    >8956 bytes
    zc = 0  f = Up       >9153 bytes
    zc = 0  f = Bigrams  >7482 bytes
    zc = 0  f = BigEnt   >8467 bytes
    zc = 0  f = Entropy  >8438 bytes
Found better combination:
    zc = 0  f = None      6510 bytes
    IDAT size = 6510 bytes (9037 bytes decrease)
    file size = 7065 bytes (10979 bytes = 60.85% decrease)
Output: /tmp/test.png
# Original image ==> reduced with pngquant ==> pngquant image recompressed with zopflipng CLI tool.
-rw-r--r-- 1 ghuls domain users 18044 Dez  1  2021 test.original.png
-rw-r--r-- 1 ghuls domain users  7761 Dez  1  2021 test.pngquant.png
-rw-r--r-- 1 ghuls domain users  6963 Dez  1  2021 test.pngquant_with_zopflipng.png

# Original image ==> reduced with oxipng (with -Z option) ==> oxipng image recompressed with zopflipng CLI tool.
-rw-r--r-- 1 ghuls domain users 18044 Dez  1  2021 test.original.png
-rw-r--r-- 1 ghuls domain users  7065 Mai  8 16:32 /tmp/test.oxipng.png
-rw-r--r-- 1 ghuls domain users 6972 Mai  8 18:44 /tmp/test_oxipng.zopflipng.png

-Z zopfli option does not work as good as the external zopflipng CLI tool for reducing the size.

@TPS
Copy link

TPS commented May 9, 2023

Be aware that there's a vast amount of work in OxiPNG since v8.0 release (& more still in-process) so, if you're not building from sources/PRs, you've still not witnessed OxiPNG's current best.

@ghuls
Copy link
Author

ghuls commented May 9, 2023

When I tested it, yesterday, I build the latest git version 2f622fc7bd610c3e8a0d2471c5d46c63f32cd626

@TPS
Copy link

TPS commented May 9, 2023

In the mean time I switched from TruePNG to pngquant + zopflipng for the specific type of images I had (final filesize was very close to TruePNG + zopflipng.

-Z zopfli option does not work as good as the external zopflipng CLI tool for reducing the size.

@ghuls Are all your PNGs ≤256 colors? If not, pngquant will be lossy & not a proper comparison against oxipng. A more correct comparison would be pngquant+oxipng vs pngquant+zopflipng.

@ghuls
Copy link
Author

ghuls commented May 9, 2023

@TPS Yes they are. They are very simple PNG images made with weblogo: https://weblogo.threeplusone.com/examples.html#splice

Maybe you didn't see it well, oxipng (oxipng -v -v --strip=all -o max -Z --out /tmp/test.png test.png) generates a smaller image than pngquant, but the image can be made smaller for both when running zopflipng on both. In the latter, the pngquant image is slightly smaller (although the -Z option should already have done a zopflipng like pass).

When comparing the pngquant and oxipng PNG files, both have 162 colors pallet and the colors are exactly the same according to imagemagick compare:

$ identify test.pngquant.png
test.pngquant.png PNG 399x199 399x199+0+0 8-bit sRGB 162c 7761B 0.000u 0:00.000

$ identify /tmp/test.oxipng.png
/tmp/test.oxipng.png PNG 399x199 399x199+0+0 8-bit sRGB 162c 7065B 0.000u 0:00.000

$ compare -metric PSNR  test.pngquant.png /tmp/test.oxipng.png /tmp/diff.png
inf

@TPS
Copy link

TPS commented May 10, 2023

but the image can be made smaller for both when running zopflipng on both.

(although the -Z option should already have done a zopflipng like pass).

IIUC, #414#495 &/or #169 (comment) would solve this, also.

@andrews05
Copy link
Collaborator

andrews05 commented May 26, 2023

@ghuls I suspect the difference may be due to palette order - oxipng only sorts by luminance while zopfli (or pngquant) may try different methods which happen to better here. Try using pngcheck -p to print the palettes and see if there's a difference.
Are you using original zopfli or a fork?

@ghuls
Copy link
Author

ghuls commented May 30, 2023

I use the original zopfli.

At first I had problems generating the same small file with pngquant + zopflipng (smallest I got was only 6972) as the one I made 2 years ago. Then I remembered that I enabled extra rounds of compresssion: zopflipng -m (6963 bytes).

When running oxipng -v -v --strip=all -o max -Z --out test.oxipng.png test.png and zopflipng -m test.oxipng.png test.oxipng.zopflipng.png, I now also get a PNG file of 6963 bytes (and the palette is in the same order as with pngquant + zopflipng ).

File: test.original.png (18044 bytes)
OK: test.original.png (399x199, 24-bit RGB, non-interlaced, 92.4%).

File: test.pngquant.png (7761 bytes)
  PLTE chunk: 162 palette entries
      0:  (255,165,  0) = (0xff,0xa5,0x00)
      1:  ( 67,161, 67) = (0x43,0xa1,0x43)
      2:  (187,221,187) = (0xbb,0xdd,0xbb)
      3:  (255,206,118) = (0xff,0xce,0x76)
      4:  (  0,  0,  0) = (0x00,0x00,0x00)
      5:  (118,187,118) = (0x76,0xbb,0x76)
      6:  (255,231,187) = (0xff,0xe7,0xbb)
      7:  (255,255,255) = (0xff,0xff,0xff)
      8:  (  0,128,  0) = (0x00,0x80,0x00)
      9:  (118,118,118) = (0x76,0x76,0x76)
     10:  (153,153,153) = (0x99,0x99,0x99)
     11:  (255,188, 67) = (0xff,0xbc,0x43)
     12:  (200,200,200) = (0xc8,0xc8,0xc8)
     13:  (187,187,187) = (0xbb,0xbb,0xbb)
     14:  (227,227,227) = (0xe3,0xe3,0xe3)
     15:  (180,180,180) = (0xb4,0xb4,0xb4)
     16:  ( 67, 67, 67) = (0x43,0x43,0x43)
     17:  (255,249,238) = (0xff,0xf9,0xee)
     18:  (255,170, 16) = (0xff,0xaa,0x10)
     19:  (118,118,255) = (0x76,0x76,0xff)
     20:  (255,219,153) = (0xff,0xdb,0x99)
     21:  (187,187,255) = (0xbb,0xbb,0xff)
     22:  ( 50,153, 50) = (0x32,0x99,0x32)
     23:  ( 16,136, 16) = (0x10,0x88,0x10)
     24:  (221,221,221) = (0xdd,0xdd,0xdd)
     25:  (238,246,238) = (0xee,0xf6,0xee)
     26:  (255,200,101) = (0xff,0xc8,0x65)
     27:  (255,237,204) = (0xff,0xed,0xcc)
     28:  (204,229,204) = (0xcc,0xe5,0xcc)
     29:  (255,194, 84) = (0xff,0xc2,0x54)
     30:  (255,243,221) = (0xff,0xf3,0xdd)
     31:  (180,156,112) = (0xb4,0x9c,0x70)
     32:  ( 33,144, 33) = (0x21,0x90,0x21)
     33:  (255,176, 33) = (0xff,0xb0,0x21)
     34:  (227,161, 40) = (0xe3,0xa1,0x28)
     35:  (255,182, 50) = (0xff,0xb6,0x32)
     36:  ( 16, 16, 16) = (0x10,0x10,0x10)
     37:  (101,178,101) = (0x65,0xb2,0x65)
     38:  ( 67, 67,255) = (0x43,0x43,0xff)
     39:  (153,204,153) = (0x99,0xcc,0x99)
     40:  (255,213,136) = (0xff,0xd5,0x88)
     41:  (170,212,170) = (0xaa,0xd4,0xaa)
     42:  (136,195,136) = (0x88,0xc3,0x88)
     43:  ( 84,170, 84) = (0x54,0xaa,0x54)
     44:  (255,225,170) = (0xff,0xe1,0xaa)
     45:  (238,238,238) = (0xee,0xee,0xee)
     46:  (255,187,187) = (0xff,0xbb,0xbb)
     47:  ( 33, 33, 33) = (0x21,0x21,0x21)
     48:  ( 50, 50, 50) = (0x32,0x32,0x32)
     49:  (204,204,204) = (0xcc,0xcc,0xcc)
     50:  (101,101,101) = (0x65,0x65,0x65)
     51:  (221,238,221) = (0xdd,0xee,0xdd)
     52:  (  0,  0,255) = (0x00,0x00,0xff)
     53:  (170,170,170) = (0xaa,0xaa,0xaa)
     54:  ( 40,134, 40) = (0x28,0x86,0x28)
     55:  (136,136,136) = (0x88,0x88,0x88)
     56:  ( 81,141, 81) = (0x51,0x8d,0x51)
     57:  (112,146,112) = (0x70,0x92,0x70)
     58:  (255,118,118) = (0xff,0x76,0x76)
     59:  (255,  0,  0) = (0xff,0x00,0x00)
     60:  (204,204,255) = (0xcc,0xcc,0xff)
     61:  (136,136,255) = (0x88,0x88,0xff)
     62:  (238,238,255) = (0xee,0xee,0xff)
     63:  (101,101,255) = (0x65,0x65,0xff)
     64:  (241,241,241) = (0xf1,0xf1,0xf1)
     65:  (214,214,214) = (0xd6,0xd6,0xd6)
     66:  (153,153,255) = (0x99,0x99,0xff)
     67:  (234,234,234) = (0xea,0xea,0xea)
     68:  (170,170,255) = (0xaa,0xaa,0xff)
     69:  ( 84, 84,255) = (0x54,0x54,0xff)
     70:  (112,112,112) = (0x70,0x70,0x70)
     71:  (221,221,255) = (0xdd,0xdd,0xff)
     72:  ( 84, 84, 84) = (0x54,0x54,0x54)
     73:  (200,158, 81) = (0xc8,0x9e,0x51)
     74:  (248,248,248) = (0xf8,0xf8,0xf8)
     75:  ( 50, 50,255) = (0x32,0x32,0xff)
     76:  (102,102,102) = (0x66,0x66,0x66)
     77:  ( 33, 33,255) = (0x21,0x21,0xff)
     78:  ( 54, 54, 54) = (0x36,0x36,0x36)
     79:  (255, 67, 67) = (0xff,0x43,0x43)
     80:  ( 16, 16,255) = (0x10,0x10,0xff)
     81:  (248,164, 10) = (0xf8,0xa4,0x0a)
     82:  (234,162, 30) = (0xea,0xa2,0x1e)
     83:  (166,166,166) = (0xa6,0xa6,0xa6)
     84:  ( 86, 86, 86) = (0x56,0x56,0x56)
     85:  ( 25, 25, 25) = (0x19,0x19,0x19)
     86:  (173,173,173) = (0xad,0xad,0xad)
     87:  (214,160, 60) = (0xd6,0xa0,0x3c)
     88:  (241,163, 20) = (0xf1,0xa3,0x14)
     89:  ( 31, 31, 31) = (0x1f,0x1f,0x1f)
     90:  (154,130,187) = (0x9a,0x82,0xbb)
     91:  (207,207,207) = (0xcf,0xcf,0xcf)
     92:  (255,221,221) = (0xff,0xdd,0xdd)
     93:  (116,162, 49) = (0x74,0xa2,0x31)
     94:  (177,202,177) = (0xb1,0xca,0xb1)
     95:  (137,137,137) = (0x89,0x89,0x89)
     96:  (191,175, 54) = (0xbf,0xaf,0x36)
     97:  ( 60,137, 60) = (0x3c,0x89,0x3c)
     98:  (234,195,124) = (0xea,0xc3,0x7c)
     99:  ( 40, 40, 40) = (0x28,0x28,0x28)
    100:  (255,101,101) = (0xff,0x65,0x65)
    101:  ( 17, 17, 17) = (0x11,0x11,0x11)
    102:  (209,202,124) = (0xd1,0xca,0x7c)
    103:  ( 89,158, 89) = (0x59,0x9e,0x59)
    104:  (139,159,139) = (0x8b,0x9f,0x8b)
    105:  ( 39, 39, 39) = (0x27,0x27,0x27)
    106:  (192,196,192) = (0xc0,0xc4,0xc0)
    107:  ( 92, 92, 92) = (0x5c,0x5c,0x5c)
    108:  (200,174,128) = (0xc8,0xae,0x80)
    109:  (248,220,168) = (0xf8,0xdc,0xa8)
    110:  (159,159,159) = (0x9f,0x9f,0x9f)
    111:  (193,193,193) = (0xc1,0xc1,0xc1)
    112:  (234,171, 56) = (0xea,0xab,0x38)
    113:  (180,172,157) = (0xb4,0xac,0x9d)
    114:  (180,167,143) = (0xb4,0xa7,0x8f)
    115:  (180,160,125) = (0xb4,0xa0,0x7d)
    116:  (180,173,162) = (0xb4,0xad,0xa2)
    117:  (175,177,175) = (0xaf,0xb1,0xaf)
    118:  (248,202,120) = (0xf8,0xca,0x78)
    119:  (227,183,102) = (0xe3,0xb7,0x66)
    120:  (162,162,162) = (0xa2,0xa2,0xa2)
    121:  ( 63, 63, 63) = (0x3f,0x3f,0x3f)
    122:  (  8,  8,  8) = (0x08,0x08,0x08)
    123:  (125,153,125) = (0x7d,0x99,0x7d)
    124:  (227,210,177) = (0xe3,0xd2,0xb1)
    125:  (180,157,116) = (0xb4,0x9d,0x74)
    126:  (191,217,174) = (0xbf,0xd9,0xae)
    127:  (227,223,215) = (0xe3,0xdf,0xd7)
    128:  (127,177,127) = (0x7f,0xb1,0x7f)
    129:  (227,165, 52) = (0xe3,0xa5,0x34)
    130:  (173,159,135) = (0xad,0x9f,0x87)
    131:  (159,154,146) = (0x9f,0x9a,0x92)
    132:  (223,191, 86) = (0xdf,0xbf,0x56)
    133:  (151,191,117) = (0x97,0xbf,0x75)
    134:  (207,159, 71) = (0xcf,0x9f,0x47)
    135:  (114,171,114) = (0x72,0xab,0x72)
    136:  (173,155,122) = (0xad,0x9b,0x7a)
    137:  (121,150,121) = (0x79,0x96,0x79)
    138:  (148,164,148) = (0x94,0xa4,0x94)
    139:  (127,185,110) = (0x7f,0xb9,0x6e)
    140:  (125,159,125) = (0x7d,0x9f,0x7d)
    141:  (111,153,111) = (0x6f,0x99,0x6f)
    142:  ( 97,148, 97) = (0x61,0x94,0x61)
    143:  (120,184,120) = (0x78,0xb8,0x78)
    144:  (162,171,162) = (0xa2,0xab,0xa2)
    145:  (168,184,168) = (0xa8,0xb8,0xa8)
    146:  (130,155,130) = (0x82,0x9b,0x82)
    147:  (181,176, 63) = (0xb5,0xb0,0x3f)
    148:  ( 10,129, 10) = (0x0a,0x81,0x0a)
    149:  (163,179, 78) = (0xa3,0xb3,0x4e)
    150:  (122,148,122) = (0x7a,0x94,0x7a)
    151:  (136,184,102) = (0x88,0xb8,0x66)
    152:  (124,180,124) = (0x7c,0xb4,0x7c)
    153:  ( 30,132, 30) = (0x1e,0x84,0x1e)
    154:  (154,181, 86) = (0x9a,0xb5,0x56)
    155:  (200,177,136) = (0xc8,0xb1,0x88)
    156:  ( 20,131, 20) = (0x14,0x83,0x14)
    157:  (200,172,120) = (0xc8,0xac,0x78)
    158:  (142,151,142) = (0x8e,0x97,0x8e)
    159:  ( 14, 14, 14) = (0x0e,0x0e,0x0e)
    160:  (174,214,174) = (0xae,0xd6,0xae)
    161:  (255, 84, 84) = (0xff,0x54,0x54)
OK: test.pngquant.png (399x199, 8-bit palette, non-interlaced, 90.2%).

File: test.pngquant.zopflipng.png (6963 bytes)
  PLTE chunk: 162 palette entries
      0:  (255,255,255) = (0xff,0xff,0xff)
      1:  (153,153,153) = (0x99,0x99,0x99)
      2:  (118,118,118) = (0x76,0x76,0x76)
      3:  (187,187,187) = (0xbb,0xbb,0xbb)
      4:  (101,101,101) = (0x65,0x65,0x65)
      5:  (  0,  0,  0) = (0x00,0x00,0x00)
      6:  ( 50, 50, 50) = (0x32,0x32,0x32)
      7:  (204,204,204) = (0xcc,0xcc,0xcc)
      8:  ( 16, 16, 16) = (0x10,0x10,0x10)
      9:  (221,221,221) = (0xdd,0xdd,0xdd)
     10:  ( 33, 33, 33) = (0x21,0x21,0x21)
     11:  (136,136,136) = (0x88,0x88,0x88)
     12:  (238,238,238) = (0xee,0xee,0xee)
     13:  ( 67, 67, 67) = (0x43,0x43,0x43)
     14:  ( 40, 40, 40) = (0x28,0x28,0x28)
     15:  (170,170,170) = (0xaa,0xaa,0xaa)
     16:  ( 84, 84, 84) = (0x54,0x54,0x54)
     17:  (234,234,234) = (0xea,0xea,0xea)
     18:  (227,227,227) = (0xe3,0xe3,0xe3)
     19:  (200,200,200) = (0xc8,0xc8,0xc8)
     20:  (180,180,180) = (0xb4,0xb4,0xb4)
     21:  (166,166,166) = (0xa6,0xa6,0xa6)
     22:  (248,248,248) = (0xf8,0xf8,0xf8)
     23:  ( 67,161, 67) = (0x43,0xa1,0x43)
     24:  (  0,128,  0) = (0x00,0x80,0x00)
     25:  ( 40,134, 40) = (0x28,0x86,0x28)
     26:  (101,178,101) = (0x65,0xb2,0x65)
     27:  ( 81,141, 81) = (0x51,0x8d,0x51)
     28:  (241,241,241) = (0xf1,0xf1,0xf1)
     29:  (193,193,193) = (0xc1,0xc1,0xc1)
     30:  (118,187,118) = (0x76,0xbb,0x76)
     31:  (153,204,153) = (0x99,0xcc,0x99)
     32:  ( 16,136, 16) = (0x10,0x88,0x10)
     33:  (214,214,214) = (0xd6,0xd6,0xd6)
     34:  (192,196,192) = (0xc0,0xc4,0xc0)
     35:  (112,146,112) = (0x70,0x92,0x70)
     36:  (168,184,168) = (0xa8,0xb8,0xa8)
     37:  ( 33,144, 33) = (0x21,0x90,0x21)
     38:  (187,221,187) = (0xbb,0xdd,0xbb)
     39:  ( 31, 31, 31) = (0x1f,0x1f,0x1f)
     40:  ( 86, 86, 86) = (0x56,0x56,0x56)
     41:  (238,246,238) = (0xee,0xf6,0xee)
     42:  (136,195,136) = (0x88,0xc3,0x88)
     43:  (162,171,162) = (0xa2,0xab,0xa2)
     44:  (175,177,175) = (0xaf,0xb1,0xaf)
     45:  (255,231,187) = (0xff,0xe7,0xbb)
     46:  (255,206,118) = (0xff,0xce,0x76)
     47:  (255,200,101) = (0xff,0xc8,0x65)
     48:  (255,219,153) = (0xff,0xdb,0x99)
     49:  (255,249,238) = (0xff,0xf9,0xee)
     50:  (177,202,177) = (0xb1,0xca,0xb1)
     51:  (241,163, 20) = (0xf1,0xa3,0x14)
     52:  (214,160, 60) = (0xd6,0xa0,0x3c)
     53:  (255,165,  0) = (0xff,0xa5,0x00)
     54:  (255,182, 50) = (0xff,0xb6,0x32)
     55:  (255,237,204) = (0xff,0xed,0xcc)
     56:  (255,176, 33) = (0xff,0xb0,0x21)
     57:  (180,156,112) = (0xb4,0x9c,0x70)
     58:  (255,170, 16) = (0xff,0xaa,0x10)
     59:  (255,213,136) = (0xff,0xd5,0x88)
     60:  (227,161, 40) = (0xe3,0xa1,0x28)
     61:  (255,243,221) = (0xff,0xf3,0xdd)
     62:  (255,225,170) = (0xff,0xe1,0xaa)
     63:  (255,188, 67) = (0xff,0xbc,0x43)
     64:  ( 50,153, 50) = (0x32,0x99,0x32)
     65:  (255,194, 84) = (0xff,0xc2,0x54)
     66:  (248,220,168) = (0xf8,0xdc,0xa8)
     67:  (248,164, 10) = (0xf8,0xa4,0x0a)
     68:  (200,174,128) = (0xc8,0xae,0x80)
     69:  (234,195,124) = (0xea,0xc3,0x7c)
     70:  (234,162, 30) = (0xea,0xa2,0x1e)
     71:  (204,229,204) = (0xcc,0xe5,0xcc)
     72:  (159,159,159) = (0x9f,0x9f,0x9f)
     73:  (173,173,173) = (0xad,0xad,0xad)
     74:  (170,212,170) = (0xaa,0xd4,0xaa)
     75:  (207,207,207) = (0xcf,0xcf,0xcf)
     76:  (221,238,221) = (0xdd,0xee,0xdd)
     77:  ( 84,170, 84) = (0x54,0xaa,0x54)
     78:  (124,180,124) = (0x7c,0xb4,0x7c)
     79:  (120,184,120) = (0x78,0xb8,0x78)
     80:  ( 30,132, 30) = (0x1e,0x84,0x1e)
     81:  ( 10,129, 10) = (0x0a,0x81,0x0a)
     82:  ( 20,131, 20) = (0x14,0x83,0x14)
     83:  ( 60,137, 60) = (0x3c,0x89,0x3c)
     84:  (234,171, 56) = (0xea,0xab,0x38)
     85:  (200,158, 81) = (0xc8,0x9e,0x51)
     86:  (130,155,130) = (0x82,0x9b,0x82)
     87:  (142,151,142) = (0x8e,0x97,0x8e)
     88:  (122,148,122) = (0x7a,0x94,0x7a)
     89:  (139,159,139) = (0x8b,0x9f,0x8b)
     90:  ( 89,158, 89) = (0x59,0x9e,0x59)
     91:  (248,202,120) = (0xf8,0xca,0x78)
     92:  ( 17, 17, 17) = (0x11,0x11,0x11)
     93:  (  8,  8,  8) = (0x08,0x08,0x08)
     94:  (207,159, 71) = (0xcf,0x9f,0x47)
     95:  (173,155,122) = (0xad,0x9b,0x7a)
     96:  (162,162,162) = (0xa2,0xa2,0xa2)
     97:  (137,137,137) = (0x89,0x89,0x89)
     98:  ( 63, 63, 63) = (0x3f,0x3f,0x3f)
     99:  (180,160,125) = (0xb4,0xa0,0x7d)
    100:  (180,172,157) = (0xb4,0xac,0x9d)
    101:  (180,173,162) = (0xb4,0xad,0xa2)
    102:  (180,167,143) = (0xb4,0xa7,0x8f)
    103:  (159,154,146) = (0x9f,0x9a,0x92)
    104:  (173,159,135) = (0xad,0x9f,0x87)
    105:  (180,157,116) = (0xb4,0x9d,0x74)
    106:  (227,165, 52) = (0xe3,0xa5,0x34)
    107:  (227,210,177) = (0xe3,0xd2,0xb1)
    108:  (227,223,215) = (0xe3,0xdf,0xd7)
    109:  (227,183,102) = (0xe3,0xb7,0x66)
    110:  ( 54, 54, 54) = (0x36,0x36,0x36)
    111:  (200,172,120) = (0xc8,0xac,0x78)
    112:  (200,177,136) = (0xc8,0xb1,0x88)
    113:  ( 97,148, 97) = (0x61,0x94,0x61)
    114:  (114,171,114) = (0x72,0xab,0x72)
    115:  (125,159,125) = (0x7d,0x9f,0x7d)
    116:  (111,153,111) = (0x6f,0x99,0x6f)
    117:  (127,177,127) = (0x7f,0xb1,0x7f)
    118:  (121,150,121) = (0x79,0x96,0x79)
    119:  (148,164,148) = (0x94,0xa4,0x94)
    120:  (125,153,125) = (0x7d,0x99,0x7d)
    121:  (116,162, 49) = (0x74,0xa2,0x31)
    122:  (209,202,124) = (0xd1,0xca,0x7c)
    123:  (223,191, 86) = (0xdf,0xbf,0x56)
    124:  (191,217,174) = (0xbf,0xd9,0xae)
    125:  (154,181, 86) = (0x9a,0xb5,0x56)
    126:  (191,175, 54) = (0xbf,0xaf,0x36)
    127:  (163,179, 78) = (0xa3,0xb3,0x4e)
    128:  (127,185,110) = (0x7f,0xb9,0x6e)
    129:  (136,184,102) = (0x88,0xb8,0x66)
    130:  (181,176, 63) = (0xb5,0xb0,0x3f)
    131:  (151,191,117) = (0x97,0xbf,0x75)
    132:  (174,214,174) = (0xae,0xd6,0xae)
    133:  (238,238,255) = (0xee,0xee,0xff)
    134:  (170,170,255) = (0xaa,0xaa,0xff)
    135:  (118,118,255) = (0x76,0x76,0xff)
    136:  ( 67, 67,255) = (0x43,0x43,0xff)
    137:  ( 16, 16,255) = (0x10,0x10,0xff)
    138:  ( 50, 50,255) = (0x32,0x32,0xff)
    139:  (  0,  0,255) = (0x00,0x00,0xff)
    140:  (153,153,255) = (0x99,0x99,0xff)
    141:  (255,187,187) = (0xff,0xbb,0xbb)
    142:  (255,118,118) = (0xff,0x76,0x76)
    143:  (255, 84, 84) = (0xff,0x54,0x54)
    144:  (255, 67, 67) = (0xff,0x43,0x43)
    145:  (255,101,101) = (0xff,0x65,0x65)
    146:  (204,204,255) = (0xcc,0xcc,0xff)
    147:  (101,101,255) = (0x65,0x65,0xff)
    148:  ( 84, 84,255) = (0x54,0x54,0xff)
    149:  (136,136,255) = (0x88,0x88,0xff)
    150:  (187,187,255) = (0xbb,0xbb,0xff)
    151:  (221,221,255) = (0xdd,0xdd,0xff)
    152:  (154,130,187) = (0x9a,0x82,0xbb)
    153:  (255,  0,  0) = (0xff,0x00,0x00)
    154:  ( 33, 33,255) = (0x21,0x21,0xff)
    155:  (255,221,221) = (0xff,0xdd,0xdd)
    156:  ( 92, 92, 92) = (0x5c,0x5c,0x5c)
    157:  ( 39, 39, 39) = (0x27,0x27,0x27)
    158:  ( 25, 25, 25) = (0x19,0x19,0x19)
    159:  ( 14, 14, 14) = (0x0e,0x0e,0x0e)
    160:  (112,112,112) = (0x70,0x70,0x70)
    161:  (102,102,102) = (0x66,0x66,0x66)
OK: test.pngquant.zopflipng.png (399x199, 8-bit palette, non-interlaced, 91.2%).

File: test.oxipng.png (7065 bytes)
  PLTE chunk: 162 palette entries
      0:  (255,255,255) = (0xff,0xff,0xff)
      1:  (255,249,238) = (0xff,0xf9,0xee)
      2:  (248,248,248) = (0xf8,0xf8,0xf8)
      3:  (255,243,221) = (0xff,0xf3,0xdd)
      4:  (238,246,238) = (0xee,0xf6,0xee)
      5:  (241,241,241) = (0xf1,0xf1,0xf1)
      6:  (238,238,255) = (0xee,0xee,0xff)
      7:  (255,237,204) = (0xff,0xed,0xcc)
      8:  (238,238,238) = (0xee,0xee,0xee)
      9:  (234,234,234) = (0xea,0xea,0xea)
     10:  (255,231,187) = (0xff,0xe7,0xbb)
     11:  (255,221,221) = (0xff,0xdd,0xdd)
     12:  (221,238,221) = (0xdd,0xee,0xdd)
     13:  (255,225,170) = (0xff,0xe1,0xaa)
     14:  (227,227,227) = (0xe3,0xe3,0xe3)
     15:  (221,221,255) = (0xdd,0xdd,0xff)
     16:  (227,223,215) = (0xe3,0xdf,0xd7)
     17:  (248,220,168) = (0xf8,0xdc,0xa8)
     18:  (255,219,153) = (0xff,0xdb,0x99)
     19:  (221,221,221) = (0xdd,0xdd,0xdd)
     20:  (204,229,204) = (0xcc,0xe5,0xcc)
     21:  (255,213,136) = (0xff,0xd5,0x88)
     22:  (214,214,214) = (0xd6,0xd6,0xd6)
     23:  (227,210,177) = (0xe3,0xd2,0xb1)
     24:  (255,206,118) = (0xff,0xce,0x76)
     25:  (204,204,255) = (0xcc,0xcc,0xff)
     26:  (255,187,187) = (0xff,0xbb,0xbb)
     27:  (207,207,207) = (0xcf,0xcf,0xcf)
     28:  (187,221,187) = (0xbb,0xdd,0xbb)
     29:  (248,202,120) = (0xf8,0xca,0x78)
     30:  (255,200,101) = (0xff,0xc8,0x65)
     31:  (191,217,174) = (0xbf,0xd9,0xae)
     32:  (204,204,204) = (0xcc,0xcc,0xcc)
     33:  (200,200,200) = (0xc8,0xc8,0xc8)
     34:  (255,194, 84) = (0xff,0xc2,0x54)
     35:  (234,195,124) = (0xea,0xc3,0x7c)
     36:  (174,214,174) = (0xae,0xd6,0xae)
     37:  (209,202,124) = (0xd1,0xca,0x7c)
     38:  (187,187,255) = (0xbb,0xbb,0xff)
     39:  (170,212,170) = (0xaa,0xd4,0xaa)
     40:  (192,196,192) = (0xc0,0xc4,0xc0)
     41:  (255,188, 67) = (0xff,0xbc,0x43)
     42:  (193,193,193) = (0xc1,0xc1,0xc1)
     43:  (177,202,177) = (0xb1,0xca,0xb1)
     44:  (255,182, 50) = (0xff,0xb6,0x32)
     45:  (223,191, 86) = (0xdf,0xbf,0x56)
     46:  (187,187,187) = (0xbb,0xbb,0xbb)
     47:  (227,183,102) = (0xe3,0xb7,0x66)
     48:  (255,176, 33) = (0xff,0xb0,0x21)
     49:  (153,204,153) = (0x99,0xcc,0x99)
     50:  (180,180,180) = (0xb4,0xb4,0xb4)
     51:  (170,170,255) = (0xaa,0xaa,0xff)
     52:  (200,177,136) = (0xc8,0xb1,0x88)
     53:  (255,170, 16) = (0xff,0xaa,0x10)
     54:  (168,184,168) = (0xa8,0xb8,0xa8)
     55:  (234,171, 56) = (0xea,0xab,0x38)
     56:  (200,174,128) = (0xc8,0xae,0x80)
     57:  (175,177,175) = (0xaf,0xb1,0xaf)
     58:  (200,172,120) = (0xc8,0xac,0x78)
     59:  (180,173,162) = (0xb4,0xad,0xa2)
     60:  (255,165,  0) = (0xff,0xa5,0x00)
     61:  (173,173,173) = (0xad,0xad,0xad)
     62:  (180,172,157) = (0xb4,0xac,0x9d)
     63:  (248,164, 10) = (0xf8,0xa4,0x0a)
     64:  (227,165, 52) = (0xe3,0xa5,0x34)
     65:  (136,195,136) = (0x88,0xc3,0x88)
     66:  (151,191,117) = (0x97,0xbf,0x75)
     67:  (241,163, 20) = (0xf1,0xa3,0x14)
     68:  (170,170,170) = (0xaa,0xaa,0xaa)
     69:  (234,162, 30) = (0xea,0xa2,0x1e)
     70:  (180,167,143) = (0xb4,0xa7,0x8f)
     71:  (162,171,162) = (0xa2,0xab,0xa2)
     72:  (227,161, 40) = (0xe3,0xa1,0x28)
     73:  (166,166,166) = (0xa6,0xa6,0xa6)
     74:  (191,175, 54) = (0xbf,0xaf,0x36)
     75:  (214,160, 60) = (0xd6,0xa0,0x3c)
     76:  (153,153,255) = (0x99,0x99,0xff)
     77:  (181,176, 63) = (0xb5,0xb0,0x3f)
     78:  (207,159, 71) = (0xcf,0x9f,0x47)
     79:  (163,179, 78) = (0xa3,0xb3,0x4e)
     80:  (154,181, 86) = (0x9a,0xb5,0x56)
     81:  (162,162,162) = (0xa2,0xa2,0xa2)
     82:  (180,160,125) = (0xb4,0xa0,0x7d)
     83:  (200,158, 81) = (0xc8,0x9e,0x51)
     84:  (173,159,135) = (0xad,0x9f,0x87)
     85:  (136,184,102) = (0x88,0xb8,0x66)
     86:  (180,157,116) = (0xb4,0x9d,0x74)
     87:  (127,185,110) = (0x7f,0xb9,0x6e)
     88:  (159,159,159) = (0x9f,0x9f,0x9f)
     89:  (255,118,118) = (0xff,0x76,0x76)
     90:  (118,187,118) = (0x76,0xbb,0x76)
     91:  (180,156,112) = (0xb4,0x9c,0x70)
     92:  (120,184,120) = (0x78,0xb8,0x78)
     93:  (148,164,148) = (0x94,0xa4,0x94)
     94:  (124,180,124) = (0x7c,0xb4,0x7c)
     95:  (173,155,122) = (0xad,0x9b,0x7a)
     96:  (127,177,127) = (0x7f,0xb1,0x7f)
     97:  (159,154,146) = (0x9f,0x9a,0x92)
     98:  (153,153,153) = (0x99,0x99,0x99)
     99:  (139,159,139) = (0x8b,0x9f,0x8b)
    100:  (136,136,255) = (0x88,0x88,0xff)
    101:  (114,171,114) = (0x72,0xab,0x72)
    102:  (142,151,142) = (0x8e,0x97,0x8e)
    103:  (255,101,101) = (0xff,0x65,0x65)
    104:  (101,178,101) = (0x65,0xb2,0x65)
    105:  (125,159,125) = (0x7d,0x9f,0x7d)
    106:  (130,155,130) = (0x82,0x9b,0x82)
    107:  (154,130,187) = (0x9a,0x82,0xbb)
    108:  (125,153,125) = (0x7d,0x99,0x7d)
    109:  (121,150,121) = (0x79,0x96,0x79)
    110:  (122,148,122) = (0x7a,0x94,0x7a)
    111:  (137,137,137) = (0x89,0x89,0x89)
    112:  (136,136,136) = (0x88,0x88,0x88)
    113:  (111,153,111) = (0x6f,0x99,0x6f)
    114:  (116,162, 49) = (0x74,0xa2,0x31)
    115:  (255, 84, 84) = (0xff,0x54,0x54)
    116:  ( 84,170, 84) = (0x54,0xaa,0x54)
    117:  (118,118,255) = (0x76,0x76,0xff)
    118:  (112,146,112) = (0x70,0x92,0x70)
    119:  ( 89,158, 89) = (0x59,0x9e,0x59)
    120:  ( 97,148, 97) = (0x61,0x94,0x61)
    121:  (255, 67, 67) = (0xff,0x43,0x43)
    122:  ( 67,161, 67) = (0x43,0xa1,0x43)
    123:  (101,101,255) = (0x65,0x65,0xff)
    124:  (118,118,118) = (0x76,0x76,0x76)
    125:  ( 81,141, 81) = (0x51,0x8d,0x51)
    126:  (112,112,112) = (0x70,0x70,0x70)
    127:  ( 50,153, 50) = (0x32,0x99,0x32)
    128:  ( 60,137, 60) = (0x3c,0x89,0x3c)
    129:  ( 84, 84,255) = (0x54,0x54,0xff)
    130:  (102,102,102) = (0x66,0x66,0x66)
    131:  (101,101,101) = (0x65,0x65,0x65)
    132:  ( 33,144, 33) = (0x21,0x90,0x21)
    133:  ( 40,134, 40) = (0x28,0x86,0x28)
    134:  ( 92, 92, 92) = (0x5c,0x5c,0x5c)
    135:  ( 30,132, 30) = (0x1e,0x84,0x1e)
    136:  ( 67, 67,255) = (0x43,0x43,0xff)
    137:  ( 16,136, 16) = (0x10,0x88,0x10)
    138:  ( 86, 86, 86) = (0x56,0x56,0x56)
    139:  ( 20,131, 20) = (0x14,0x83,0x14)
    140:  ( 84, 84, 84) = (0x54,0x54,0x54)
    141:  ( 10,129, 10) = (0x0a,0x81,0x0a)
    142:  (255,  0,  0) = (0xff,0x00,0x00)
    143:  (  0,128,  0) = (0x00,0x80,0x00)
    144:  ( 50, 50,255) = (0x32,0x32,0xff)
    145:  ( 67, 67, 67) = (0x43,0x43,0x43)
    146:  ( 63, 63, 63) = (0x3f,0x3f,0x3f)
    147:  ( 33, 33,255) = (0x21,0x21,0xff)
    148:  ( 54, 54, 54) = (0x36,0x36,0x36)
    149:  ( 50, 50, 50) = (0x32,0x32,0x32)
    150:  ( 16, 16,255) = (0x10,0x10,0xff)
    151:  ( 40, 40, 40) = (0x28,0x28,0x28)
    152:  ( 39, 39, 39) = (0x27,0x27,0x27)
    153:  ( 33, 33, 33) = (0x21,0x21,0x21)
    154:  ( 31, 31, 31) = (0x1f,0x1f,0x1f)
    155:  (  0,  0,255) = (0x00,0x00,0xff)
    156:  ( 25, 25, 25) = (0x19,0x19,0x19)
    157:  ( 17, 17, 17) = (0x11,0x11,0x11)
    158:  ( 16, 16, 16) = (0x10,0x10,0x10)
    159:  ( 14, 14, 14) = (0x0e,0x0e,0x0e)
    160:  (  8,  8,  8) = (0x08,0x08,0x08)
    161:  (  0,  0,  0) = (0x00,0x00,0x00)
OK: test.oxipng.png (399x199, 8-bit palette, non-interlaced, 91.1%).

File: test.oxipng.zopflipng.png (6963 bytes)
  PLTE chunk: 162 palette entries
      0:  (255,255,255) = (0xff,0xff,0xff)
      1:  (153,153,153) = (0x99,0x99,0x99)
      2:  (118,118,118) = (0x76,0x76,0x76)
      3:  (187,187,187) = (0xbb,0xbb,0xbb)
      4:  (101,101,101) = (0x65,0x65,0x65)
      5:  (  0,  0,  0) = (0x00,0x00,0x00)
      6:  ( 50, 50, 50) = (0x32,0x32,0x32)
      7:  (204,204,204) = (0xcc,0xcc,0xcc)
      8:  ( 16, 16, 16) = (0x10,0x10,0x10)
      9:  (221,221,221) = (0xdd,0xdd,0xdd)
     10:  ( 33, 33, 33) = (0x21,0x21,0x21)
     11:  (136,136,136) = (0x88,0x88,0x88)
     12:  (238,238,238) = (0xee,0xee,0xee)
     13:  ( 67, 67, 67) = (0x43,0x43,0x43)
     14:  ( 40, 40, 40) = (0x28,0x28,0x28)
     15:  (170,170,170) = (0xaa,0xaa,0xaa)
     16:  ( 84, 84, 84) = (0x54,0x54,0x54)
     17:  (234,234,234) = (0xea,0xea,0xea)
     18:  (227,227,227) = (0xe3,0xe3,0xe3)
     19:  (200,200,200) = (0xc8,0xc8,0xc8)
     20:  (180,180,180) = (0xb4,0xb4,0xb4)
     21:  (166,166,166) = (0xa6,0xa6,0xa6)
     22:  (248,248,248) = (0xf8,0xf8,0xf8)
     23:  ( 67,161, 67) = (0x43,0xa1,0x43)
     24:  (  0,128,  0) = (0x00,0x80,0x00)
     25:  ( 40,134, 40) = (0x28,0x86,0x28)
     26:  (101,178,101) = (0x65,0xb2,0x65)
     27:  ( 81,141, 81) = (0x51,0x8d,0x51)
     28:  (241,241,241) = (0xf1,0xf1,0xf1)
     29:  (193,193,193) = (0xc1,0xc1,0xc1)
     30:  (118,187,118) = (0x76,0xbb,0x76)
     31:  (153,204,153) = (0x99,0xcc,0x99)
     32:  ( 16,136, 16) = (0x10,0x88,0x10)
     33:  (214,214,214) = (0xd6,0xd6,0xd6)
     34:  (192,196,192) = (0xc0,0xc4,0xc0)
     35:  (112,146,112) = (0x70,0x92,0x70)
     36:  (168,184,168) = (0xa8,0xb8,0xa8)
     37:  ( 33,144, 33) = (0x21,0x90,0x21)
     38:  (187,221,187) = (0xbb,0xdd,0xbb)
     39:  ( 31, 31, 31) = (0x1f,0x1f,0x1f)
     40:  ( 86, 86, 86) = (0x56,0x56,0x56)
     41:  (238,246,238) = (0xee,0xf6,0xee)
     42:  (136,195,136) = (0x88,0xc3,0x88)
     43:  (162,171,162) = (0xa2,0xab,0xa2)
     44:  (175,177,175) = (0xaf,0xb1,0xaf)
     45:  (255,231,187) = (0xff,0xe7,0xbb)
     46:  (255,206,118) = (0xff,0xce,0x76)
     47:  (255,200,101) = (0xff,0xc8,0x65)
     48:  (255,219,153) = (0xff,0xdb,0x99)
     49:  (255,249,238) = (0xff,0xf9,0xee)
     50:  (177,202,177) = (0xb1,0xca,0xb1)
     51:  (241,163, 20) = (0xf1,0xa3,0x14)
     52:  (214,160, 60) = (0xd6,0xa0,0x3c)
     53:  (255,165,  0) = (0xff,0xa5,0x00)
     54:  (255,182, 50) = (0xff,0xb6,0x32)
     55:  (255,237,204) = (0xff,0xed,0xcc)
     56:  (255,176, 33) = (0xff,0xb0,0x21)
     57:  (180,156,112) = (0xb4,0x9c,0x70)
     58:  (255,170, 16) = (0xff,0xaa,0x10)
     59:  (255,213,136) = (0xff,0xd5,0x88)
     60:  (227,161, 40) = (0xe3,0xa1,0x28)
     61:  (255,243,221) = (0xff,0xf3,0xdd)
     62:  (255,225,170) = (0xff,0xe1,0xaa)
     63:  (255,188, 67) = (0xff,0xbc,0x43)
     64:  ( 50,153, 50) = (0x32,0x99,0x32)
     65:  (255,194, 84) = (0xff,0xc2,0x54)
     66:  (248,220,168) = (0xf8,0xdc,0xa8)
     67:  (248,164, 10) = (0xf8,0xa4,0x0a)
     68:  (200,174,128) = (0xc8,0xae,0x80)
     69:  (234,195,124) = (0xea,0xc3,0x7c)
     70:  (234,162, 30) = (0xea,0xa2,0x1e)
     71:  (204,229,204) = (0xcc,0xe5,0xcc)
     72:  (159,159,159) = (0x9f,0x9f,0x9f)
     73:  (173,173,173) = (0xad,0xad,0xad)
     74:  (170,212,170) = (0xaa,0xd4,0xaa)
     75:  (207,207,207) = (0xcf,0xcf,0xcf)
     76:  (221,238,221) = (0xdd,0xee,0xdd)
     77:  ( 84,170, 84) = (0x54,0xaa,0x54)
     78:  (124,180,124) = (0x7c,0xb4,0x7c)
     79:  (120,184,120) = (0x78,0xb8,0x78)
     80:  ( 30,132, 30) = (0x1e,0x84,0x1e)
     81:  ( 10,129, 10) = (0x0a,0x81,0x0a)
     82:  ( 20,131, 20) = (0x14,0x83,0x14)
     83:  ( 60,137, 60) = (0x3c,0x89,0x3c)
     84:  (234,171, 56) = (0xea,0xab,0x38)
     85:  (200,158, 81) = (0xc8,0x9e,0x51)
     86:  (130,155,130) = (0x82,0x9b,0x82)
     87:  (142,151,142) = (0x8e,0x97,0x8e)
     88:  (122,148,122) = (0x7a,0x94,0x7a)
     89:  (139,159,139) = (0x8b,0x9f,0x8b)
     90:  ( 89,158, 89) = (0x59,0x9e,0x59)
     91:  (248,202,120) = (0xf8,0xca,0x78)
     92:  ( 17, 17, 17) = (0x11,0x11,0x11)
     93:  (  8,  8,  8) = (0x08,0x08,0x08)
     94:  (207,159, 71) = (0xcf,0x9f,0x47)
     95:  (173,155,122) = (0xad,0x9b,0x7a)
     96:  (162,162,162) = (0xa2,0xa2,0xa2)
     97:  (137,137,137) = (0x89,0x89,0x89)
     98:  ( 63, 63, 63) = (0x3f,0x3f,0x3f)
     99:  (180,160,125) = (0xb4,0xa0,0x7d)
    100:  (180,172,157) = (0xb4,0xac,0x9d)
    101:  (180,173,162) = (0xb4,0xad,0xa2)
    102:  (180,167,143) = (0xb4,0xa7,0x8f)
    103:  (159,154,146) = (0x9f,0x9a,0x92)
    104:  (173,159,135) = (0xad,0x9f,0x87)
    105:  (180,157,116) = (0xb4,0x9d,0x74)
    106:  (227,165, 52) = (0xe3,0xa5,0x34)
    107:  (227,210,177) = (0xe3,0xd2,0xb1)
    108:  (227,223,215) = (0xe3,0xdf,0xd7)
    109:  (227,183,102) = (0xe3,0xb7,0x66)
    110:  ( 54, 54, 54) = (0x36,0x36,0x36)
    111:  (200,172,120) = (0xc8,0xac,0x78)
    112:  (200,177,136) = (0xc8,0xb1,0x88)
    113:  ( 97,148, 97) = (0x61,0x94,0x61)
    114:  (114,171,114) = (0x72,0xab,0x72)
    115:  (125,159,125) = (0x7d,0x9f,0x7d)
    116:  (111,153,111) = (0x6f,0x99,0x6f)
    117:  (127,177,127) = (0x7f,0xb1,0x7f)
    118:  (121,150,121) = (0x79,0x96,0x79)
    119:  (148,164,148) = (0x94,0xa4,0x94)
    120:  (125,153,125) = (0x7d,0x99,0x7d)
    121:  (116,162, 49) = (0x74,0xa2,0x31)
    122:  (209,202,124) = (0xd1,0xca,0x7c)
    123:  (223,191, 86) = (0xdf,0xbf,0x56)
    124:  (191,217,174) = (0xbf,0xd9,0xae)
    125:  (154,181, 86) = (0x9a,0xb5,0x56)
    126:  (191,175, 54) = (0xbf,0xaf,0x36)
    127:  (163,179, 78) = (0xa3,0xb3,0x4e)
    128:  (127,185,110) = (0x7f,0xb9,0x6e)
    129:  (136,184,102) = (0x88,0xb8,0x66)
    130:  (181,176, 63) = (0xb5,0xb0,0x3f)
    131:  (151,191,117) = (0x97,0xbf,0x75)
    132:  (174,214,174) = (0xae,0xd6,0xae)
    133:  (238,238,255) = (0xee,0xee,0xff)
    134:  (170,170,255) = (0xaa,0xaa,0xff)
    135:  (118,118,255) = (0x76,0x76,0xff)
    136:  ( 67, 67,255) = (0x43,0x43,0xff)
    137:  ( 16, 16,255) = (0x10,0x10,0xff)
    138:  ( 50, 50,255) = (0x32,0x32,0xff)
    139:  (  0,  0,255) = (0x00,0x00,0xff)
    140:  (153,153,255) = (0x99,0x99,0xff)
    141:  (255,187,187) = (0xff,0xbb,0xbb)
    142:  (255,118,118) = (0xff,0x76,0x76)
    143:  (255, 84, 84) = (0xff,0x54,0x54)
    144:  (255, 67, 67) = (0xff,0x43,0x43)
    145:  (255,101,101) = (0xff,0x65,0x65)
    146:  (204,204,255) = (0xcc,0xcc,0xff)
    147:  (101,101,255) = (0x65,0x65,0xff)
    148:  ( 84, 84,255) = (0x54,0x54,0xff)
    149:  (136,136,255) = (0x88,0x88,0xff)
    150:  (187,187,255) = (0xbb,0xbb,0xff)
    151:  (221,221,255) = (0xdd,0xdd,0xff)
    152:  (154,130,187) = (0x9a,0x82,0xbb)
    153:  (255,  0,  0) = (0xff,0x00,0x00)
    154:  ( 33, 33,255) = (0x21,0x21,0xff)
    155:  (255,221,221) = (0xff,0xdd,0xdd)
    156:  ( 92, 92, 92) = (0x5c,0x5c,0x5c)
    157:  ( 39, 39, 39) = (0x27,0x27,0x27)
    158:  ( 25, 25, 25) = (0x19,0x19,0x19)
    159:  ( 14, 14, 14) = (0x0e,0x0e,0x0e)
    160:  (112,112,112) = (0x70,0x70,0x70)
    161:  (102,102,102) = (0x66,0x66,0x66)
OK: test.oxipng.zopflipng.png (399x199, 8-bit palette, non-interlaced, 91.2%).

@andrews05
Copy link
Collaborator

andrews05 commented May 30, 2023

Right, we can see here that zopflipng gives a different palette order than oxipng by itself, which likely explains the size difference. This is probably coincidental rather zopflipng just being "better" - afaik it doesn't actually have any explicit palette sorting algorithms. Chances are oxipng will be better on average (aside from the -m flag - oxipng internal zopfli is currently fixed to 15 iterations, unless you use the API).
I have been testing some other algorithms lately though (see #514) - if you post the image I could take a look and see if they help here.

@ghuls
Copy link
Author

ghuls commented Jun 4, 2023

@andrews05 Here is the image:
factorbook__ENCSR344SBD_AGAGAGAGAGAGAGA_2 job4

@andrews05
Copy link
Collaborator

Thanks. Sadly though, the new palette sorting did not improve this image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-Medium Issues that are breaking core functionality, but have a known workaround T-Compression Relates to improving the compression ratio of images T-Feature Requests for a new feature to be added T-Meta A collection of related issues
Projects
None yet
Development

No branches or pull requests

5 participants