# Lens Test Comparison Creator # maxlyons@tawbaware.com # Max Lyons, May 2003 # # Example usage: dir /b *.jpg | perl lenstest.pl # # This script is used to make an "image comparison" page, useful for comparing # lenses. It reads a list of image names from STDIN and produces a table with # crops from the corners and center of each image. Beneath each crop it prints # the name of the lens, the aperture and focal length. The aperture and focal # length are parsed from the EXIF data embedded in the image. The lens name # must be part of the image filename and is matched with a regexp...modify as # needed. # # This script requires Perl and Image Magick to be installed and available on # the system path. # # Image Magick can be downloaded from http://www.imagemagick.org/ # Perl (for Windows) can be downloaded from http://www.activestate.com/ # #=============================================================================# # Configurable parameters...modify as desired: # The size width and height of each crop. $cropSize = 180; # Number of pixels from edge of image to position crop. $edge = 10; #Size of title font on page $titleFontSize = 24; #Size of label font on page $fontSize = 18; #Color of text on page $textColor = "#000000"; #Border between crops in final image $border = 5; # The name of the finished product (JPG used by default, but can also use # .bmp or .tif extension for lossless output format). $finalOutputName = "lens_table.jpg"; #=============================================================================# # Global vars # Array used to contain names of intermediate files used in # creation of final image. @montageFiles = (); #=============================================================================# &main(); sub appendHeader() { my $tmpOutput = @_[0]; my $p1 = $border + (0.2 * $cropSize); my $p2 = $p1 + (2 * $border) + $cropSize; my $p3 = $p2 + (2 * $border) + $cropSize; my $p4 = $p3 + (2 * $border) + $cropSize; my $p5 = $p4 + (2 * $border) + $cropSize; #Create an empty image the same width as the intermediate images $cmd = "montage -geometry ".$cropSize."x40+$border+$border -tile 5x1 NULL: NULL: NULL: NULL: NULL: \"tmp_lenstest.bmp\""; system($cmd); #Add the text labels to it $cmd = qq~convert -pointsize $titleFontSize -font Arial.ttf -fill $textColor -draw "text $p1,32 Top_Left" -draw "text $p2,32 Top_Right" -draw "text $p3,32 Center" -draw "text $p4,32 Bottom_Left" -draw "text $p5,32 Bottom_Right" "tmp_lenstest.bmp" "tmp_lenstest_label.bmp"~; system($cmd); #Append it to the top of the table $cmd = qq~convert -quality 60 "tmp_lenstest_label.bmp" "$tmpOutput" -append "$finalOutputName"~; system($cmd); #Clean up temp files $cmd = "del tmp_lenstest.bmp tmp_lenstest_label.bmp $tmpOutput"; system($cmd); } sub main() { my $tempOutputName = "tmp_output.bmp"; # Loop over STDIN reading file names while (<>) { chomp; my $filename = $_; my @commands = &makeCommands($filename); # Create intermediate files...each intermediate file contains crops # from one image print "\nProcessing $filename"; foreach $command (@commands) { system ($command); print "."; } } #Combine all the intermediate files into one final, output file print "\nCombining intermediate files"; my $fileCount = $#montageFiles+1; $cmd = "montage -tile 1x$fileCount -geometry 100%x100%+0+0"; foreach $piece (@montageFiles) { $cmd .= " \"$piece\""; } $cmd .= " $tempOutputName"; system ($cmd); # Append the header showing text labels print "\nAppending header"; &appendHeader($tempOutputName); #Clean up intermediate files print "\nCleaning up temporary files"; $cmd = "del"; foreach $piece (@montageFiles) { $cmd .= " \"$piece\""; } system ($cmd); print "\nFinished\n"; } # Returns an array of commands used to create an intermediate file consisting # of crops from one image sub makeCommands() { my $filename = @_[0]; my @commands = (); #Use the filename as the default descriptive text... my $lens = $filename; #...but try and parse out the lens manufacturer name from the filename (modify as needed) if ($filename =~ /(canon|nikon|minolta|tokina|sigma|tamron)/i) { $lens = $1; } # Extract aperture and focal length from EXIF data # (requires Image Magick to be installed and available on path) my ($imageWidth, $imageHeight, $aperture, $flen) = split(/\|/, `identify -format \"%w|%h|%[EXIF:FNumber]|%[EXIF:FocalLength]" \"$filename\"`); $flen = eval($flen) . "mm"; $aperture = "F" . eval($aperture); # Temporary files containing cropped portions (tl=top left, bl=bottom left, # tr=top right, br=bottom right, ct=center) my $tl = "$filename\.tl\.bmp"; my $bl = "$filename\.bl\.bmp"; my $tr = "$filename\.tr\.bmp"; my $br = "$filename\.br\.bmp"; my $ct = "$filename\.ct\.bmp"; my $outputName = "$filename\.montage\.bmp"; # construct commands to crop image # (requires Image Magick to be installed and available on path) my $cmd = "convert -crop $cropSize"."x"."$cropSize"; push @commands, "$cmd" . "+$edge+$edge \"$filename\" \"$tl\""; push @commands, "$cmd" . "+$edge+" . ($imageHeight-$edge-$cropSize) . " \"$filename\" \"$bl\""; push @commands, "$cmd" . "+" . ($imageWidth/2-$cropSize/2) . "+" . ($imageHeight/2-$cropSize/2) . " \"$filename\" \"$ct\""; push @commands, "$cmd" . "+" . ($imageWidth-$edge-$cropSize) . "+" . ($imageHeight-$edge-$cropSize) . " \"$filename\" \"$br\""; push @commands, "$cmd" . "+" . ($imageWidth-$edge-$cropSize) . "+$edge" . " \"$filename\" \"$tr\""; # Combine the individual crops made above into one intermediate image push @commands, "montage -geometry $cropSizex$cropSize+$border+$border -tile 5x1 -font Arial.ttf -pointsize $fontSize -fill $textColor -label \"$lens|$flen|$aperture\" \"$tl\" \"$tr\" \"$ct\" \"$bl\" \"$br\" \"$outputName\""; # Clean up the individual crops push @commands, "del \"$tl\" \"$tr\" \"$bl\" \"$br\" \"$ct\""; # Remember the name of the combined image push @montageFiles, "$outputName"; return @commands; }