‘optiPNG’ vs ‘PNGcrush’ vs ‘Gimp’ to Reduce PNG Size
Which is better? NEITHER! optipng and pngcrush are dated tools, but they are free, and surprisingly still work. Here are some comparisons on compression levels on a PNG file vs the same file as JPG format.
Page load speed is important as a ranking factor in search engines. It makes sense therefore, to optimize your page for speed. While a CDN is probably the better solution, it doesn’t hurt to ALSO optimize your png files.
I was using cygwin and noticed a few tools related to optimizing png files, and how reducing png size:
- optipng
- pngcrush
I’m used to using other tools such as gimp and ifranview to reduce png size before but thought these tools were worth investigating at least.
TLDR
(Not suprisingly) jpg was a better format for web work but I liked optipng better if I had to choose between pngcrush and optipng. Both beat out gimp, unless I used indexed colors, which only work on specific types of images. Gimp > Export > rename as .jpg, save!
Lossy vs Lossless
JPG is “lossy” meaning, it compresses the data in a way where some of the original data is gone and can never be retrieved.
PNG is “lossless” meaning, you can save (nearly) all of the original data.
Transparency
No such thing as a transparent background in jpgs, but PNGs can preserve this layer.
OptiPNG Results
Opti PNG shows me “as-it-happens” as it tries different filters and optimization methods. I liked this. I also like the display of
1 |
$ optipng -o7 -keep pngtest.png |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
** Processing: pngtest.png 500x515 pixels, 4x8 bits/pixel, RGB+alpha Reducing image to 3x8 bits/pixel, RGB Input IDAT size = 306918 bytes Input file size = 307419 bytes Trying: zc = 9 zm = 9 zs = 0 f = 1 IDAT size = 287339 zc = 9 zm = 9 zs = 0 f = 2 IDAT size = 283790 zc = 9 zm = 9 zs = 0 f = 3 IDAT size = 276206 zc = 9 zm = 9 zs = 0 f = 4 IDAT size = 274093 zc = 9 zm = 9 zs = 0 f = 5 IDAT size = 273103 Selecting parameters: zc = 9 zm = 9 zs = 0 f = 5 IDAT size = 273103 Output IDAT size = 273103 bytes (33815 bytes decrease) Output file size = 273160 bytes (34259 bytes = 11.14% decrease) |
PNGcrush results
PNG crush doesn’t give me as much info but it does tell me CPU time, which is nice.
1 |
$ pngcrush -brute pngtest.original.png |
1 2 3 4 |
Recompressing IDAT chunks in pngtest.original.png to pngout.png Total length of data found in critical chunks = 307419 Best pngcrush method = 118 (ws 15 fm 5 zl 9 zs 0) = 273160 CPU time decode 1.205000, encode 4.921000, other 0.246000, total 6.718000 sec |
Smallest PNG Size Results?
1 |
$ file pngtest.original.png |
1 |
pngtest.original.png: PNG image data, 500 x 515, 8-bit/color RGBA, non-interlaced |
It is entirely possible that there are different results based on file size, image type, image complexity etc. I didn’t test thoroughly and just picked an image instead.
Original PNG (301k)
Indexed PNG (61k)
Optimized PNG (267k)
JPG (71k)
To be fair though, jpg is lossy, and others are not (with the obvious exception of indexed).
Batch Processing
This wouldn’t even be worth talking about without a way to automate it right? Who wants to manually process 3,142 png files?
1 |
$ ls -alFh |
1 2 3 4 |
-rwxrwx---+ 1 david None 92K Sep 7 10:14 1-barrel-sandponics.png* -rwxrwx---+ 1 david None 196K Sep 7 10:15 1-barrel-sandponics2.png* -rwxrwx---+ 1 david None 116K Sep 7 10:16 1-barrel-sandponics-back.png* -rwxrwx---+ 1 david None 101K Sep 7 10:15 1-barrel-sandponics-bottom.png* |
For Loop in Shell
Process all png files using optipng and keep backups. The for loop in the shell uses the f variable to replace the file names on each loop:
1 |
$ for f in *.png; do optipng -keep -o7 $f;done |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
** Processing: 1-barrel-sandponics.png 321x573 pixels, 4x8 bits/pixel, RGB+alpha Reducing image to 3x8 bits/pixel, RGB Input IDAT size = 93262 bytes Input file size = 93381 bytes Trying: zc = 9 zm = 9 zs = 0 f = 0 IDAT size = 78323 zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 78238 zc = 9 zm = 9 zs = 0 f = 4 IDAT size = 75392 zc = 9 zm = 9 zs = 0 f = 5 IDAT size = 74314 Selecting parameters: zc = 9 zm = 9 zs = 0 f = 5 IDAT size = 74314 Output IDAT size = 74314 bytes (18948 bytes decrease) Output file size = 74421 bytes (18960 bytes = 20.30% decrease) ** Processing: 1-barrel-sandponics2.png 363x747 pixels, 4x8 bits/pixel, RGB+alpha Reducing image to 3x8 bits/pixel, RGB Input IDAT size = 200112 bytes Input file size = 200255 bytes Trying: zc = 9 zm = 9 zs = 0 f = 0 IDAT size = 172896 zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 171951 zc = 9 zm = 9 zs = 0 f = 4 IDAT size = 170537 zc = 9 zm = 8 zs = 0 f = 4 IDAT size = 170046 zc = 9 zm = 8 zs = 0 f = 5 IDAT size = 169767 Selecting parameters: zc = 9 zm = 8 zs = 0 f = 5 IDAT size = 169767 Output IDAT size = 169767 bytes (30345 bytes decrease) Output file size = 169874 bytes (30381 bytes = 15.17% decrease) ** Processing: 1-barrel-sandponics-back.png 353x545 pixels, 4x8 bits/pixel, RGB+alpha Reducing image to 3x8 bits/pixel, RGB Input IDAT size = 117985 bytes Input file size = 118104 bytes Trying: zc = 9 zm = 9 zs = 0 f = 0 IDAT size = 104402 zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 104205 Selecting parameters: zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 104205 Output IDAT size = 104205 bytes (13780 bytes decrease) Output file size = 104312 bytes (13792 bytes = 11.68% decrease) ** Processing: 1-barrel-sandponics-bottom.png 393x409 pixels, 4x8 bits/pixel, RGB+alpha Reducing image to 3x8 bits/pixel, RGB Input IDAT size = 102431 bytes Input file size = 102550 bytes Trying: zc = 9 zm = 9 zs = 0 f = 0 IDAT size = 89245 Selecting parameters: zc = 9 zm = 9 zs = 0 f = 0 IDAT size = 89245 Output IDAT size = 89245 bytes (13186 bytes decrease) Output file size = 89352 bytes (13198 bytes = 12.87% decrease) |
After the loop does it’s thing, you have results of the original copied to a .bak file and the new file available for you:
1 2 3 4 5 6 7 8 |
-rw-rw-r--+ 1 david None 73K Oct 13 18:11 1-barrel-sandponics.png -rwxrwx---+ 1 david None 92K Sep 7 10:14 1-barrel-sandponics.png.bak* -rw-rw-r--+ 1 david None 166K Oct 13 18:11 1-barrel-sandponics2.png -rwxrwx---+ 1 david None 196K Sep 7 10:15 1-barrel-sandponics2.png.bak* -rw-rw-r--+ 1 david None 102K Oct 13 18:12 1-barrel-sandponics-back.png -rwxrwx---+ 1 david None 116K Sep 7 10:16 1-barrel-sandponics-back.png.bak* -rw-rw-r--+ 1 david None 88K Oct 13 18:12 1-barrel-sandponics-bottom.png -rwxrwx---+ 1 david None 101K Sep 7 10:15 1-barrel-sandponics-bottom.png.bak* |