#!/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 <text>] [-headerright <text>] <files> # 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 <title>] [-headerleft <text>] [-headerright <text>] <files>\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;