O'Reilly

PNGCRUSH a Directory of Images

By on  

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.

Track.js Error Reporting

Upcoming Events

Recent Features

  • Write Simple, Elegant and Maintainable Media Queries with Sass

    I spent a few months experimenting with different approaches for writing simple, elegant and maintainable media queries with Sass. Each solution had something that I really liked, but I couldn't find one that covered everything I needed to do, so I ventured into creating my...

  • I’m an Impostor

    This is the hardest thing I've ever had to write, much less admit to myself.  I've written resignation letters from jobs I've loved, I've ended relationships, I've failed at a host of tasks, and let myself down in my life.  All of those feelings were very...

Incredible Demos

  • Duplicate the jQuery Homepage Tooltips Using Dojo

    The jQuery homepage has a pretty suave tooltip-like effect as seen below: Here's how to accomplish this same effect using Dojo. The XHTML The above HTML was taken directly from the jQuery homepage -- no changes. The CSS The above CSS has been slightly modified to match the CSS rules already...

  • 5 More HTML5 APIs You Didnât Know Existed

    The HTML5 revolution has provided us some awesome JavaScript and HTML APIs.  Some are APIs we knew we've needed for years, others are cutting edge mobile and desktop helpers.  Regardless of API strength or purpose, anything to help us better do our job is a...

Discussion

  1. 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

  2. Holy crap. In my defense this was a really late night post. Weak. My bad.

  3. Robbo

    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.

  4. Ben

    Is there a way to do this with PHP? Or something a bit more practical?

  5. @Ben: What’s impractical about this?

  6. @David Walsh: I don’t know how to run bash scripts :)

  7. Oh — in that case, try this:

    http://pornel.net/imageoptim/en

  8. rick

    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!

  9. jon wilson

    i think this was a great post. it has helped me much. thank you

  10. Very useful script!

  11. 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.

  12. 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

  13. 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.

  14. 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.

  15. files

    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)

  16. files

    4 months and no-one’s answered me… This problem really annoys me. It seems that pngcrush’s missing some packing methods…

  17. 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.

  18. 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.

  19. sloppp

    says “illegal option n” or something like dat

    this works for me

    pngcrush -d crushed_png *.png
    cp crushed_png/*.png .
    rm -rf crushed_png
    

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!

Recently on David Walsh Blog

  • Intercept HTTP Requests with Node.js nock

    Unit testing external APIs is difficult no matter what language you do it in.  Hell, working with any external API is scary, if only because you have zero control of networking issues, API changes, and a host of other issues.  But if you do create a service...

  • Introducing Frontend Masters (with Giveaway)

    Hey DWB readers, I'm super happy to sponsor this blog. I've been a long-time reader and fan, since back when David wrote about JavaScript and MooTools back in 2007. ;-) We are in one of the fastest changing, evolving, most lively communities on earth: JavaScript and front-end web...

  • Get Node.js Command Line Arguments with yargs

    Using command line arguments within Node.js apps is par for the course, especially when you're like me and you use JavaScript to code tasks (instead of bash scripts).  Node.js provides process.argv but that doesn't provide a key: value object like you'd expect: Bleh.  If you want to work with a...

  • OâReilly Velocity Conference â New York

    My favorite front-end conference has always been O'Reilly's Velocity Conference because the conference series has focused on one of the most undervalued parts of client side coding:  speed.  So often we're so excited that our JavaScript works that we forget that speed, efficiency, and performance are just as important. The next Velocity...

  • Free Download: Font Bundle Featuring 17 Incredible Typefaces

    The only thing we love more than a good font, is a good free font. So we’ve combed the Web for some of our favorite free fonts, and gathered them here in a single download. You’ll find a variety of useful typefaces, from highly geometric designs...