#!/usr/bin/perl
### Generate a contact sheet (index print) for a given set of images ###
# (C) 2006, Eli Glanz
###
# This script relies on the PerlMagick API; for more documentation see:
# http://imagemagick.org/script/perl-magick.php
# This script relies on the ExifTool API; for more documentation see:
# http://www.sno.phy.queensu.ca/~phil/exiftool/
###
# Command line arguments:
# contact-sheet.pl [-title
] [-headerleft ] [-headerright ]
# title: title text to add to the contact sheet
# headerleft: left-header text to add to the contact sheet
# headerright: right-header text to add to the contact sheet
# file: image files to add to the contact sheet
use strict;
use Image::Magick;
use Image::ExifTool;
sub showHelp {
print "$0 [-title ] [-headerleft ] [-headerright ] \n";
print "\ttitle: title text to add to the contact sheet\n";
print "\theaderleft: left-header text to add to the contact sheet\n";
print "\theaderright: right-header text to add to the contact sheet\n";
print "\tfile: images file to add to the contact sheet\n";
}
my $TILES_WIDE = 5;
my $TILE_WIDTH = 425;
my $TILES_HIGH = 6;
my $TILE_HEIGHT = 425;
my $TEMP_DIR = ".contact-tmp";
my (@files, $SHEET_HEADER_LEFT, $SHEET_HEADER_RIGHT, $SHEET_TITLE, $status);
# process the command line
while (my $arg = shift) {
if (-f $arg) {
push @files, $arg;
} elsif ("-title" eq $arg) {
$SHEET_TITLE = shift @ARGV;
} elsif ("-headerleft" eq $arg) {
$SHEET_HEADER_LEFT = shift @ARGV;
} elsif ("-headerrightt" eq $arg) {
$SHEET_HEADER_RIGHT = shift @ARGV;
} else {
print "Unrecognized argument: $arg\n\n";
showHelp;
exit 1;
}
}
if ($#files == -1) {
showHelp;
exit 1;
}
@files = sort @files;
mkdir $TEMP_DIR;
my $images=Image::Magick->new;
my $tileCount = $TILES_WIDE * $TILES_HIGH;
my $fileCount = $#files;
my $contactSheetNumber = 1;
my $contactSheetCount = $fileCount/$tileCount;
$contactSheetCount++ if ($fileCount%$tileCount > 0);
# to speed up processing, we only send to ImageMagick a list of the individual files it needs to be concerned with
while ($fileCount > -1) {
print "Generating contact sheet ".$contactSheetNumber." of ".int($contactSheetCount);
my $startTime = time;
my @montageFiles;
# shrink all the input files to speed the creation of the contact sheet
for (my $i=0; $i<$tileCount; $i++) {
my $fileName = shift @files;
if (defined $fileName) {
my $images=Image::Magick->new;
my $status = $images->Read($fileName);
$status = $images->Resize($TILE_WIDTH.'x'.$TILE_HEIGHT.'>');
$status = $images->Set(density => '300', quality => '50');
$status = $images->Write($TEMP_DIR.'/'.$fileName);
undef $images;
push @montageFiles, $TEMP_DIR.'/'.$fileName;
}
}
print "."; sleep 1;
my $contactSheetFileName = 'contact-sheet-'.$contactSheetNumber.'.jpg';
my $images=Image::Magick->new;
my $exifTool = new Image::ExifTool;
my $info;
# load each thumbnail created above
foreach my $fileName (@montageFiles) {
$info = $exifTool->ImageInfo($fileName);
my $thumbnail=Image::Magick->new;
$status = $thumbnail->Read($fileName);
$status = $thumbnail->Label($$info{'CreateDate'});
push(@$images, $thumbnail);
undef $thumbnail;
}
# set the montage properties
my $montage=$images->Montage(tile => $TILES_WIDE."x".$TILES_HIGH,
geometry => $TILE_WIDTH.'x'.$TILE_HEIGHT.'+4+2>',
pointsize => '36',
label => '%t\n%l');
# write the contact sheet at 300dpi, with low compression
$montage->Set(density => '300', quality => '80');
$status = $montage->Write($contactSheetFileName);
undef $images;
print "."; sleep 1;
my $image=Image::Magick->new;
$status = $image->Read($contactSheetFileName);
# set the background for the page header
$status = $image->Draw(primitive => 'rectangle', gravity => 'North', method => 'FloodFill', fill => '#EEEEEE', stroke => '#FFFFFF', points => '0,0 '.$montage->Get('width').',53');
# add the right header (if any)
$status = $image->Annotate(pointsize => 20, gravity => 'NorthEast', x => 0, y => 10, text => $SHEET_HEADER_RIGHT." ") if (defined $SHEET_HEADER_RIGHT);
# add the title (if any)
$status = $image->Annotate(pointsize => 40, gravity => 'North', text => $SHEET_TITLE) if (defined $SHEET_TITLE);
# add the left header (if any)
$status = $image->Annotate(pointsize => 20, gravity => 'NorthWest', x => 0, y => 10, text => " ".$SHEET_HEADER_LEFT) if (defined $SHEET_HEADER_LEFT);
$status = $image->Write($contactSheetFileName);
undef $montage;
undef $image;
print "."; sleep 1;
# delete the temporary files created above
unlink @montageFiles;
print "."; sleep 1;
my $endTime = time;
my $totalTime = ($endTime-$startTime);
print $totalTime."s\n";
$fileCount = $#files;
$contactSheetNumber++;
}
rmdir $TEMP_DIR;