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”