PNGCRUSH a Directory of Images
One easy way of reducing website load time is by optimizing your images. PNG graphics are often more bloated than they need to be so using PNGCRUSH should be a no-brainer. PNGCRUSH's basic usage provides only single-file-crushage but I've created a script that crushes PNGs in directories recursively.
The Bash Script
#!/bin/sh
for png in `find $1 -name "*.png"`;
do
echo "crushing $png"
pngcrush -brute "$png" temp.png
mv -f temp.png $png
done;
Do whatever you can to compress your images so that your website will load as quickly as possible. PNGCRUSHing your images does not cause a loss of quality -- only a loss of excess file size! PNGCRUSHing my images saved over 120KB of bloated imagery for the recent redesign.
For maximum performance, we all know we must put our assets on CDN (another domain). Along with those assets are custom web fonts. Unfortunately custom web fonts via CDN (or any cross-domain font request) don't work in Firefox or Internet Explorer (correctly so, by spec) though...
The <canvas>
element has been a revelation for the visual experts among our ranks. Canvas provides the means for incredible and efficient animations with the added bonus of no Flash; these developers can flash their awesome JavaScript skills instead. Here are nine unbelievable canvas demos that...
Thomas Fuchs, creator of script2 (scriptaculous' second iteration) and Zepto.js (mobile JavaScript framework), creates outstanding animated elements with JavaScript. He's a legend in his own right, and for good reason: his work has helped to inspire developers everywhere to drop Flash and opt...
One of the reasons I love AJAX technology so much is because it allows us to avoid unnecessary page loads. Why download the header, footer, and other static data multiple times if that specific data never changes? It's a waste of time, processing, and bandwidth. Unfortunately...
heh, this post is so engrish: “so that your website load as quickly” and “does not cause a lose of quality”. mootools crew must be whipping you hard then :)
pngcrush… was this something you found on your mac thingie? most inconsiderate of “normal” windows users :D
Holy crap. In my defense this was a really late night post. Weak. My bad.
Totally untested, but for windows users, as long as everything is in the one spot….
Create a batch file called “crush.bat”
Put the following code in it.
@echo off
for /f “tokens=*” %%x in (‘dir /b *.png’) do (
echo “crushing %%x”
pngcrush -brute “%%x” temp.png
move /Y temp.png “%%x”
)
Then run it.
Is there a way to do this with PHP? Or something a bit more practical?
@Ben: What’s impractical about this?
@David Walsh: I don’t know how to run bash scripts :)
Oh — in that case, try this:
http://pornel.net/imageoptim/en
It’s even easier than that, pngcrush supports * for selecting images to crush. Try: ‘pngcrush -d “/Users/rd/crushedimages/” *.png’ to crush ALL png images in the current directory and put the resulting files in “/Users/rd/crushedimages/” (change this to a directory of your choosing!
i think this was a great post. it has helped me much. thank you
Very useful script!
In terms of usability and performance, under windoes, it doesn’t get better than this for a gui – http://pnggauntlet.com
a great feature is that you can simply drag/ drop images, and it will ‘smash’ them,a nd overwrite the original files on the fly.
for example, pull your entire website to a local folder, search for *.png in win explorer, then simply drag/ drop the query results into pnggauntlet, making sure to check the ‘overwrite original files’ box, and let it smash down the file size.
i just tested this workflow on a massive ecommerce website (about 2700 png’s worth about 40mb) and saved a whopping 3mb. of course, who knows how well the originals were optimized, but nonetheless, it’s a great result.
another great feature is that it can optionally convert from jpg, tiff, gif and bmp to png.
I was searching for some information on jpgcrush and google assumed I meant pngcrush… Anyway for anyone who is interested I have several tutorials on this subject (in python) one of which will make use of multiple processors (which saves quite a bit of time if you have a tonne of pngs.)
http://www.ragingsloth.com/softwareEng/PNGOptimizerIndex.html
Simplest way to do this.
1. Create a folder for executables which will go into your PATH directory reference.
2. Open folder containing PNGs you want to crush
3. shift + right click in empty space in folder, “open command window in folder”
4. type “pngcrush -d “crushed” *.png
5. close command window and go to newly created ‘crushed’ folder, which now contains your optimised PNGs.
Simplest way to do this.
1. Make sure that pngcrush.exe is in a folder which is mentioned in the PATH directory reference, so it can be used from the command line.
2. Open folder containing PNGs you want to crush.
3. shift + right click in empty space in folder, “open command window in folder”
4. type “pngcrush -d “crushed” *.png
5. close command window and go to newly created ‘crushed’ folder, which now contains your optimised PNGs.
How to get it to abort if file size will be INCREASED?!
| pngcrush 1.7.9
| Copyright (C) 1998-2002,2006-2010 Glenn Randers-Pehrson
| Copyright (C) 2005 Greg Roelofs
| This is a free, open-source program. Permission is irrevocably
| granted to everyone to use this version of pngcrush without
| payment of any fee.
| Executable name is pngcrush
| It was built with libpng version 1.2.42, and is
| running with libpng version 1.2.46 - July 9, 2011
| Copyright (C) 1998-2004,2006-2010 Glenn Randers-Pehrson,
| Copyright (C) 1996, 1997 Andreas Dilger,
| Copyright (C) 1995, Guy Eric Schalnat, Group 42 Inc.,
| and zlib version 1.2.3.3, Copyright (C) 1998-2002 (or later),
| Jean-loup Gailly and Mark Adler.
|| Warning: versions are different between png.h and png.c
|| png.h version: 1.2.42
|| png.c version: 1.2.46
| It was compiled with gcc version 4.4.4 and gas version 2.9.5(?).
Recompressing wut.png
Total length of data found in IDAT chunks = 548746
color counting (-cc option) is not supported.
Removed the pHYs chunk.
unknown chunk handling done.
IDAT length with method 11 (fm 0 zl 2 zs 2) = 2435942
IDAT length with method 12 (fm 1 zl 2 zs 2) = 951323
IDAT length with method 13 (fm 2 zl 2 zs 2) = 905037
IDAT length with method 14 (fm 3 zl 2 zs 2) = 1016476
IDAT length with method 15 (fm 4 zl 2 zs 2) = 858259
IDAT length with method 16 (fm 5 zl 2 zs 2) = 846721
IDAT length with method 17 (fm 0 zl 1 zs 0) = 697832
IDAT length with method 18 (fm 1 zl 1 zs 0) = 797697
IDAT length with method 19 (fm 2 zl 1 zs 0) = 755660
IDAT length with method 20 (fm 3 zl 1 zs 0) = 859270
IDAT length with method 21 (fm 4 zl 1 zs 0) = 761716
IDAT length with method 22 (fm 5 zl 1 zs 0) = 753877
IDAT length with method 23 (fm 0 zl 1 zs 1) = 697832
IDAT length with method 24 (fm 1 zl 1 zs 1) = 797697
IDAT length with method 25 (fm 2 zl 1 zs 1) = 755660
IDAT length with method 26 (fm 3 zl 1 zs 1) = 859270
IDAT length with method 27 (fm 4 zl 1 zs 1) = 761716
IDAT length with method 28 (fm 5 zl 1 zs 1) = 753877
IDAT length with method 29 (fm 0 zl 2 zs 0) = 673435
IDAT length with method 30 (fm 1 zl 2 zs 0) = 765510
IDAT length with method 31 (fm 2 zl 2 zs 0) = 731611
IDAT length with method 32 (fm 3 zl 2 zs 0) = 835291
IDAT length with method 33 (fm 4 zl 2 zs 0) = 735487
IDAT length with method 34 (fm 5 zl 2 zs 0) = 729097
IDAT length with method 35 (fm 0 zl 2 zs 1) = 673435
IDAT length with method 36 (fm 1 zl 2 zs 1) = 765510
IDAT length with method 37 (fm 2 zl 2 zs 1) = 731611
IDAT length with method 38 (fm 3 zl 2 zs 1) = 835291
IDAT length with method 39 (fm 4 zl 2 zs 1) = 735487
IDAT length with method 40 (fm 5 zl 2 zs 1) = 729097
IDAT length with method 41 (fm 0 zl 3 zs 0) = 654550
IDAT length with method 42 (fm 1 zl 3 zs 0) = 710763
IDAT length with method 43 (fm 2 zl 3 zs 0) = 694884
IDAT length with method 44 (fm 3 zl 3 zs 0) = 791240
IDAT length with method 45 (fm 4 zl 3 zs 0) = 694167
IDAT length with method 46 (fm 5 zl 3 zs 0) = 692165
IDAT length with method 47 (fm 0 zl 3 zs 1) = 654550
IDAT length with method 48 (fm 1 zl 3 zs 1) = 710763
IDAT length with method 49 (fm 2 zl 3 zs 1) = 694884
IDAT length with method 50 (fm 3 zl 3 zs 1) = 791240
IDAT length with method 51 (fm 4 zl 3 zs 1) = 694167
IDAT length with method 52 (fm 5 zl 3 zs 1) = 692165
IDAT length with method 53 (fm 0 zl 4 zs 0) = 587966
IDAT length with method 54 (fm 1 zl 4 zs 0) = 695367
IDAT length with method 55 (fm 2 zl 4 zs 0) = 672502
IDAT length with method 56 (fm 3 zl 4 zs 0) = 771732
IDAT length with method 57 (fm 4 zl 4 zs 0) = 675596
IDAT length with method 58 (fm 5 zl 4 zs 0) = 670186
IDAT length with method 59 (fm 0 zl 4 zs 1) = 634611
IDAT length with method 60 (fm 1 zl 4 zs 1) = 698306
IDAT length with method 61 (fm 2 zl 4 zs 1) = 688376
IDAT length with method 62 (fm 3 zl 4 zs 1) = 785595
IDAT length with method 63 (fm 4 zl 4 zs 1) = 680116
IDAT length with method 64 (fm 5 zl 4 zs 1) = 674963
IDAT length with method 65 (fm 0 zl 5 zs 0) = 567961
IDAT length with method 66 (fm 1 zl 5 zs 0) = 659745
IDAT length with method 67 (fm 2 zl 5 zs 0) = 651320
IDAT length with method 68 (fm 3 zl 5 zs 0) = 745437
IDAT length with method 69 (fm 4 zl 5 zs 0) = 648498
IDAT length with method 70 (fm 5 zl 5 zs 0) = 645942
IDAT length with method 71 (fm 0 zl 5 zs 1) = 615134
IDAT length with method 72 (fm 1 zl 5 zs 1) = 667126
IDAT length with method 73 (fm 2 zl 5 zs 1) = 669886
IDAT length with method 74 (fm 3 zl 5 zs 1) = 762645
IDAT length with method 75 (fm 4 zl 5 zs 1) = 658031
IDAT length with method 76 (fm 5 zl 5 zs 1) = 655619
IDAT length with method 77 (fm 0 zl 6 zs 0) = 560413
IDAT length with method 78 (fm 1 zl 6 zs 0) = 618874
IDAT length with method 79 (fm 2 zl 6 zs 0) = 623842
IDAT length with method 80 (fm 3 zl 6 zs 0) = 710951
IDAT length with method 81 (fm 4 zl 6 zs 0) = 618249
IDAT length with method 82 (fm 5 zl 6 zs 0) = 619695
IDAT length with method 83 (fm 0 zl 6 zs 1) = 606769
IDAT length with method 84 (fm 1 zl 6 zs 1) = 627807
IDAT length with method 85 (fm 2 zl 6 zs 1) = 643727
IDAT length with method 86 (fm 3 zl 6 zs 1) = 730353
IDAT length with method 87 (fm 4 zl 6 zs 1) = 629654
IDAT length with method 88 (fm 5 zl 6 zs 1) = 630925
IDAT length with method 89 (fm 0 zl 7 zs 0) = 558547
IDAT length with method 90 (fm 1 zl 7 zs 0) = 605505
IDAT length with method 91 (fm 2 zl 7 zs 0) = 612292
IDAT length with method 92 (fm 3 zl 7 zs 0) = 695889
IDAT length with method 93 (fm 4 zl 7 zs 0) = 608946
IDAT length with method 94 (fm 5 zl 7 zs 0) = 610519
IDAT length with method 95 (fm 0 zl 7 zs 1) = 604538
IDAT length with method 96 (fm 1 zl 7 zs 1) = 614662
IDAT length with method 97 (fm 2 zl 7 zs 1) = 631610
IDAT length with method 98 (fm 3 zl 7 zs 1) = 714922
IDAT length with method 99 (fm 4 zl 7 zs 1) = 620061
IDAT length with method 100 (fm 5 zl 7 zs 1) = 621519
IDAT length with method 101 (fm 0 zl 8 zs 0) = 555261
IDAT length with method 102 (fm 1 zl 8 zs 0) = 589149
IDAT length with method 103 (fm 2 zl 8 zs 0) = 597092
IDAT length with method 104 (fm 3 zl 8 zs 0) = 676219
IDAT length with method 105 (fm 4 zl 8 zs 0) = 596852
IDAT length with method 106 (fm 5 zl 8 zs 0) = 598205
IDAT length with method 107 (fm 0 zl 8 zs 1) = 600862
IDAT length with method 108 (fm 1 zl 8 zs 1) = 597438
IDAT length with method 109 (fm 2 zl 8 zs 1) = 614670
IDAT length with method 110 (fm 3 zl 8 zs 1) = 693766
IDAT length with method 111 (fm 4 zl 8 zs 1) = 606835
IDAT length with method 112 (fm 5 zl 8 zs 1) = 607756
IDAT length with method 113 (fm 0 zl 9 zs 0) = 554346
IDAT length with method 114 (fm 1 zl 9 zs 0) = 578629
IDAT length with method 115 (fm 2 zl 9 zs 0) = 587438
IDAT length with method 116 (fm 3 zl 9 zs 0) = 665646
IDAT length with method 117 (fm 4 zl 9 zs 0) = 586698
IDAT length with method 118 (fm 5 zl 9 zs 0) = 588334
IDAT length with method 119 (fm 0 zl 9 zs 1) = 599719
IDAT length with method 120 (fm 1 zl 9 zs 1) = 586780
IDAT length with method 121 (fm 2 zl 9 zs 1) = 603901
IDAT length with method 122 (fm 3 zl 9 zs 1) = 683089
IDAT length with method 123 (fm 4 zl 9 zs 1) = 595879
IDAT length with method 124 (fm 5 zl 9 zs 1) = 597310
IDAT length with method 125 (fm 0 zl 1 zs 3) = 2246417
IDAT length with method 126 (fm 1 zl 1 zs 3) = 876458
IDAT length with method 127 (fm 2 zl 1 zs 3) = 801576
IDAT length with method 128 (fm 3 zl 1 zs 3) = 940918
IDAT length with method 129 (fm 4 zl 1 zs 3) = 753268
IDAT length with method 130 (fm 5 zl 1 zs 3) = 741504
IDAT length with method 131 (fm 0 zl 4 zs 3) = 2245807
IDAT length with method 132 (fm 1 zl 4 zs 3) = 876189
IDAT length with method 133 (fm 2 zl 4 zs 3) = 801449
IDAT length with method 134 (fm 3 zl 4 zs 3) = 940635
IDAT length with method 135 (fm 4 zl 4 zs 3) = 753015
IDAT length with method 136 (fm 5 zl 4 zs 3) = 741282
Best pngcrush method = 113 (fm 0 zl 9 zs 0) for temp.png
(1.02% IDAT increase)
(1.02% filesize increase)
CPU time used = 47.830 seconds (decoding 2.470,
encoding 45.050, other 0.310 seconds)
4 months and no-one’s answered me… This problem really annoys me. It seems that pngcrush’s missing some packing methods…
Useful script! Thank you. I’d suggest changing
for png in
find $1 -name "*.png"
;to
for png in
find $1 -iname "*.png"
;in order to catch files with extensions such as .PNG and .Png.
Looks like someone “borrowed” your script:
http://www.wulf.co.nz/running-pngcrush-on-a-recursive-directories/
Everyone steals from me :(
Hey now Thomas, that’s a bit of a dick allegation! And a huge let down after I saw http://davidwalsh.name in a list of my site’s backlinks! If I’d found David’s post I would gladly have used his tools rather than spend a few minutes writing my own which I then posted to my site to save it should I need it again. But, you know, if a famous guy said a similar thing before me and I didn’t see or hear it, then I “must” be stealing it. Ugh.
The two scripts aim to achieve the exact same goal using the same most obvious choice tools (find, do while, mv), and use the same most obvious variable names – ‘temp’ for the temp file and ‘png’ for the singular entry in the list of pngs. If you tasked 100 competent developers with this, 95 of them would have a very similar script, and the other 5 scripts wouldn’t work.
I’ll take it as the best compliment that my shitty little bash script can be confused as coming from *the* David Walsh, even if mine has slightly better parameter handling :p
Just a suggestion, but it probably makes sense to nice this if running on a live server. Additionally, you can speed this up *a lot* on a multicore box by passing this through xargs.
says “illegal option n” or something like dat
this works for me
UBUNTU / DEBIAN tested
Script for Bash – command
Place in your
.bashrc
of the userbe carefully : done by users rights / group rights; so by doing that with root,
output file is owned by root/root
so it makes sense to write
chkpng
inroot/.bashrc
and
write
fixpng
only in/home/user/.bashrc