Skip to content

Instantly share code, notes, and snippets.

@NoodlesNZ
Last active December 28, 2015 20:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NoodlesNZ/7556392 to your computer and use it in GitHub Desktop.
Save NoodlesNZ/7556392 to your computer and use it in GitHub Desktop.
Updated to use threads
#!/usr/bin/perl
#
# Lossless optimization for all JPEG files in a directory
#
# This script uses techniques described in this article about the use
# of jpegtran: http://www.phpied.com/installing-jpegtran-mac-unix-linux/
#
use strict;
use File::Find;
use File::Copy;
use threads;
use threads::shared;
use POSIX ();
my $MAX_PROCESSES = 10;
my @threads;
my $start_run = time();
# Read image dir from input
if (!$ARGV[0]) {
print "Usage: $0 path_to_images\n";
exit 1;
}
my @search_paths;
my $images_path = $ARGV[0];
if (!-e $images_path) {
print "Invalid path specified.\n";
exit 1;
} else {
push @search_paths, $ARGV[0];
}
my @imagefiles;
# Compress JPEGs
my $count_jpegs :shared = 0;
my $count_modified :shared = 0;
my $count_optimize :shared = 0;
my $count_progressive :shared = 0;
my $bytes_saved :shared = 0;
my $bytes_orig :shared = 0;
find(\&findImages, @search_paths);
my $perArr = POSIX::ceil(scalar(@imagefiles) / $MAX_PROCESSES);
for (my $i = 0; $i < $MAX_PROCESSES ; $i++) {
my @data = splice(@imagefiles, 0, $perArr);
my $thrd = threads->create(\&processArr, @data);
push @threads, $thrd;
}
foreach (@threads) {
$_->join;
}
# Write summary
print "\n\n";
print "----------------------------\n";
print " Sumary\n";
print "----------------------------\n";
print "\n";
print " Inspected $count_jpegs JPEG files.\n";
print " Modified $count_modified files.\n";
print " Huffman table optimizations: $count_optimize\n";
print " Progressive JPEG optimizations: $count_progressive\n";
print " Total bytes saved: $bytes_saved (orig $bytes_orig, saved "
. (int($bytes_saved/$bytes_orig*10000) / 100) . "%)\n";
print "\n";
my $end_run = time();
my $run_time = $end_run - $start_run;
print "Job took $run_time seconds\n";
sub processArr()
{
foreach (@_) {
jpegCompress($_);
}
}
sub jpegCompress()
{
if (m/\.jpg$/i) {
my $fullname = $_;
$count_jpegs++;
my $orig_size = -s $_;
my $saved = 0;
$_ =~ s/ /\\ /g;
print "Inspecting $fullname\n";
# Run Progressive JPEG and Huffman table optimizations, then inspect
# which was best.
`/usr/local/bin/jpegtran -copy none -optimize $_ > $_.opt`;
my $opt_size = -s "$_.opt";
`/usr/local/bin/jpegtran -copy none -progressive $_ > $_.prog`;
my $prog_size = -s "$_.prog";
if ($opt_size && $opt_size < $orig_size && $opt_size <= $prog_size) {
move("$_.opt", "$_");
$saved = $orig_size - $opt_size;
$bytes_saved += $saved;
$bytes_orig += $orig_size;
$count_modified++;
$count_optimize++;
print " -- Huffman table optimization: "
. "saved $saved bytes (orig $orig_size)\n";
} elsif ($prog_size && $prog_size < $orig_size) {
move("$_.prog", "$_");
$saved = $orig_size - $prog_size;
$bytes_saved += $saved;
$bytes_orig += $orig_size;
$count_modified++;
$count_progressive++;
print " -- Progressive JPEG optimization: "
. "saved $saved bytes (orig $orig_size)\n";
}
# Cleanup temp files
if (-e "$_.prog") {
unlink("$_.prog");
}
if (-e "$_.opt") {
unlink("$_.opt");
}
}
}
sub findImages()
{
my $fullname = $File::Find::dir . '/' . $_;
push(@imagefiles, $fullname);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment