Batch PNG Optimization
When designing web sites, squeezing your design down to as few kilobytes as possible is a critical operation to keep your site responsive to visitors with low-bandwidth internet connections.
In a well designed web site, markup is almost insignificant in size relative to the image files that make up a visually rich presentation. In order to create image files that are as tiny as possible, I use Ken Silverman‘s PNGOUT utility.
While PNGOUT serves my purposes very well, it has two flaws:
- No batch operation
- No support for FreeBSD
Fortunately, I can do something to address the first issue.
Below is a perl script I just finished pounding out. Given a base directory and optionally, custom pngout arguments, this script will recursively traverse through all subdirectories optimizing the PNG images via the pngout utility.
#!/usr/bin/perl use strict; use warnings; use Cwd; my $pngoutpath = "/usr/local/bin/pngout"; if (@ARGV == 2) { recurseDir ($ARGV[0], $ARGV[1]); } elsif (@ARGV == 1) { recurseDir ($ARGV[0], 0); } else { print "Usage: recursive-pngout dir [args]\n"; } sub recurseDir { my ($curpath, $args) = @_; if (opendir (CURDIR, $curpath)) { chdir ($curpath); my @files = readdir(CURDIR); closedir (CURDIR); foreach my $file (@files) { next if $file eq "."; next if $file eq ".."; recurseDir ($file, $args); } chdir ('..'); } else { if ($curpath =~ /.png$/) { my $dir = getcwd; if ($args) { system ("$pngoutpath $args $dir/$curpath"); } else { system ("$pngoutpath $dir/$curpath"); } } return; } }
I know this could have been accomplished by a shell one-liner, but my abilities with the shell are a little rusty. I also tend to think in perl when I’m tackling a quick solution to a problem.
August 10th, 2013 at 8:01 am
Thanks for the script! For interest’s sake, here’s a one-liner that works as well:
for a in $(find /var/www/html -name ‘*.png’); do /path/to/pngout -r -k0 $a; done
It’d be interesting to see if we could capture the number of bytes reduced and present a grand total at the end. I suppose a du -ks before and after would do. Let me see what I can come up with…
August 10th, 2013 at 8:43 am
A bit of a cheat because it’s really a script piled onto one line, but here it is:
dir=”/var/www/html” ; presize=`du -bs $dir | gawk ‘{ print $1 }’`Â ; for a in $(find $dir -name ‘*.png’); do /home/bobbitt/bin/pngout $a; done; postsize=`du -bs $dir | gawk ‘{ print $1 }’`Â ; diff=`expr $presize – $postsize`Â ; echo -e “Size before: $presize\nSize After: $postsize\nDifference: $diff”