Creating thumbnail images where others failed

At work I had a vexing problem: a whole bunch of users had profile images but no matching thumbnail. The cause of this condition isn’t relevant here, but read on to see the code I used to patch things up.

A particular app accepts images uploaded by users and is supposed to create a companion thumbnail for display purposes. Although it looks like the app is working, somehow a significant number of images turned out to not have the requisite thumbnail. For consistency a “default” image is used for everyone who hasn’t uploaded one. This image is signed with the name of the guy who did the default image artwork, named Mike.

To address the problem I wrote a little perl script that audits the folder where the thumbnails are stored. The script starts out by cataloging the names of the uploaded images and then walks that list, checking to see if the corresponding thumbnail is a “real” image or a copy of the default.

#!/usr/bin/perl
# Audit pics apps-auditpics.pl
# Created by P Lembo on 15 Jul 2014.

use strict;
use Image::ExifTool;
use Image::Magick;
use File::Copy;

my $HOME = $ENV{'HOME'};
my $WEBROOT = "/data/www/html/directoryapp/public";
my $profilesDir = "$WEBROOT/img/profiles";
my $thumbsDir = "$WEBROOT/img/thumbnails";
my $errfile = "$HOME/data/logs/apps-auditpics.log";
open LOGZ, ">$HOME/data/logs/$errfile";
my $timestamp = localtime();

print LOGZ $timestamp, " Directory App Pictures Audit\n";
print $timestamp, " Directory App Pictures Audit\n";
audit_pics();
close LOGZ;

sub audit_pics {
 # Get list of file names from pics directory
 opendir(DIR, "$profilesDir") or die $!;
 my @files = readdir DIR;
 closedir DIR;
 my $total =0;
 my $numdef =0;
 foreach my $filename(@files) {
   $total++;
   my $srcpath = $profilesDir . "/" . $filename;
   my $tarfile = $filename;
   for($tarfile) { s/_full//g; }
   my $tarpath = $thumbsDir . "/". $tarfile;
   my $exifTool = Image::ExifTool->new();
   $exifTool->ExtractInfo($tarpath);
   my $comment = $exifTool-&>GetValue('Comment');
   if(($comment =~ /Mike/g)&&($filename !~ /Default_full.jpg/g)) {
      print LOGZ $tarfile, "\n";
      print $tarfile, "\n";
      my $img = Image::Magick->new();
      $img->Read($srcpath);
      $img->Thumbnail(geometry=>'80x80');
      $img->Write(filename=>$tarpath);
      $numdef++;
   }
 } 
 print LOGZ $total, " is the total of all profile pics\n";
 print $total, " is the total of all profile pics\n";
 print LOGZ $numdef, " default thumbs found\n";
 print $numdef, " default thumbs found\n";
}
__END__;

A few observations about the above. When you’re dealing with potentially thousands of images it’s important to generate a record of the files the script has touched. As a result I build a very simple logging function into this script.

Image::ExifTool is a very powerful perl module that allows you to manipulate images in very useful ways. In this script I’m using it to capture the text of any Comment in the target images to determine if it matches the “signature” of the default artwork’s author. See the ExifTool home page for copious information on its use.

This was my first time using the Image::Magick module. I’d previously used the corresponding utilities on Linux, particularly the convert tool. Although identical in function to the command line tools I did have to spend some time determining the correct syntax to use. While the recommended size of uploaded images was 350x350px, resulting in thumbnails of 80x80px, it really wasn’t practical to expect our users to spend time resizing and cropping images. The app had a built in routine to scale down images that exceeded the recommended size, but inevitably that would result in images of the right width but shorter or longer height. The convert tool will accept a single parameter for geometry (“convert -thumbnail 80 bigimage.jpg thumb.jpg”), which it treats as aspirational. In my experience it does a good job of coming close to the desired dimensions.

The Image::Magick Thumbnail method takes one or more of 3 terms: geometry, width and/or height. Using either of the latter two without the other will often give rise to an unattractive result (think Funhouse mirror). It turns out that the woefully underdocumented geometry parameter is analogous to the previously cited convert syntax. When I tell the script to do “$img->Thumbnail(geometry=>’80×80′)” what it hears is “do your best to give an 80x80px result”. That worked fine for my application because I really needed it to adjust its output in accordance with the uneven nature of the sources.

My only gripe about Image::Magick (a/k/a PerlMagick) is that the author chose to ship it with HTML documentation rather than the standard POD for perl. This makes it a bit harder to use in a graphics-free environment and results in a less than usual structured presentation (although many perl module authors have done worse when paying mere lip service to POD conventions).

This entry was posted in System Administration on by .

About phil

My name is Phil Lembo. In my day job I’m an enterprise IT architect for a leading distribution and services company. The rest of my time I try to maintain a semi-normal family life in the suburbs of Raleigh, NC. E-mail me at philipATlembobrothersDOTcom. The opinions expressed here are entirely my own and not those of my employers, past, present or future (except where I quote others, who will need to accept responsibility for their own rants).