#!/usr/bin/perl # # thumbelizer # # Take a directory of photos and create thumbnails # # Required support programs: ImageMagick # Image::Size # # Credits: Inspired by Garrett LeSage's photo pages. # Html layout made to look like his output (blatent copy). # Ideas from code by Gerard Daubar and imgconvert # Design ideas from dugsong and kia # # Thumbs are generated in name_#.ext format. # denotes image number. # # (C) 2000 Jauder Ho # # 20000128 jauderho [initial whack at the code] # 20000130 jauderho [more work on it. most functions have been cleaned up] # [image reduction is now based on reduction factors instead] # [this should allow better handling of different sized pics] # 20000131 jauderho [image dimensions are now properly reportedly. people do] # [turn the camera occasionally :). first public release] # 20000203 jauderho [moved the layout around a bit which makes things cleaner] # use File::Copy cp; # Self-explanatory use Image::Size; my $setname; my $set_dir; my (%user,%default,%config); # Adjust to fit to your tastes. You *will* probably want to change these. $default{reduce_factor} = "4 3"; # reduction factor $default{thumb_size} = "112x75"; # size for thumbnails $config{html_filename} = "index.html"; # name for html file created # Edit these for sure if you don't use --interactive $default{sourcedir} = "source"; # dir where your pictures are $default{targetdir} = "target"; # dir to put finished product in $default{columns} = 4; # number of columns of images $default{page_heading} = "My Photos"; $default{page_desc} = "Some pictures I took with a camera."; $default{sliderdir} = "slides/"; # General config vars that are not prompted in --interactive mode. Adjust to # whatever you like. $config{page_bgcolor} = "#ffffff"; # color for the bg of the page $config{color_link} = "#666666"; # color for link in body tag $config{color_alink} = "#ffffff"; # color for alink in body tag $config{color_vlink} = "#999999"; # color for vlink in body tag $config{color_text} = "#000000"; # text for color $config{font} = "helvetica,arial,sans-serif"; # font for page $config{convert_xoptions} = "-quality 75"; # conver extra options $config{min_columns} = 1; # avoid an error, can ignore $config{max_columns} = 10; # avoid an error, can ignore # These are some personal prefs. You may experiment with them if you want $config{keep_filename} = 0; # Do not rename originals on copy $config{fancy_caption} = 1; # Idea originally from kia's site $config{slider_compat} = 0; # Compatibility mode with slider # # Do not go any further unless you know what you are doing. You have been # warned appropriately. # $version = "0.8"; # set version number $| = 1; # autoflush output (for progress meter) # Define subroutines sub thumbs_convert_images; sub thumbs_convert_image_sizes; sub thumbs_create_html_file; sub thumbs_create_column; sub thumbs_dir_prepare; sub thumbs_get_prefs; sub thumbs_option_check; sub thumbs_originals_copy; sub thumbs_usage; sub thumbs_version; sub process_prefs; # Start your engines... thumbs_option_check; # Check ARGV thumbs_version; # Print version # Figure out if we are in interactive mode or use the default prefs instead. ($mode_interactive) ? thumbs_get_prefs : (%user = %default); # Do some post processing on the prefs process_prefs; # Make and prep target dir thumbs_dir_prepare; thumbs_convert_images; # Convert images and place them in target dir thumbs_create_html_file; # Create the HTML thumbs_originals_copy; # Copy originals to set dir # The End # Sets user prefs sub thumbs_get_prefs { print "\n"; # Image source directory print "Image source directory [$default{sourcedir}]: "; $user{sourcedir} = ; # Image target directory print "Image target directory [$default{targetdir}]: "; $user{targetdir} = ; # Pref thumb size print "Thumb image size (WxH) [$default{thumb_size}]: "; $user{thumb_size} = ; # Set number of columns print "Number of columns for index [$default{columns}]: "; $user{columns} = ; # Page heading. We are also going to use this to print "Caption [$default{page_heading}]: "; $user{page_heading} = ; # Page description. Only ask if fancy_caption is not turned on. if ($config{fancy_caption} != 1) { print "Index description [$default{page_desc}]: "; $user{page_desc} = ; } # Reduction factor i.e. WxH reduced appropriately # Don't be silly and choose something that is not a factor print "Reduction factors [$default{reduce_factor}]: "; $user{reduce_factor} = ; # Fill in the blanks. for (keys %default) { chomp($user{$_}); $user{$_} = $default{$_} if ($user{$_} =~ /^$/); } # Start doing sanity checks and some preprocessing # Make sure that the input directory exists die "ERROR: Source directory does not exist.\n" unless (-d $user{sourcedir}); # Create the target directory if it does not already exist mkdir($user{targetdir},0755) unless (-d $user{targetdir}); # Check for reasonable # of columns die "ERROR: Bad number of columns.\n" if (($user{columns} < $config{min_columns}) || ($user{columns} > $config{max_columns})); print "\n"; } sub process_prefs { # Create @rfactors @rfactors = split(" ", $user{reduce_factor}) unless ($user{reduce_factor} =~ /none/); # Figure out the set name to put stuff in $setname = $user{page_heading}; $setname = lc($setname); $setname =~ s/\W//g; # Drop all non letters } # Creates the dir for the new set # Returns: the dir created on success sub thumbs_dir_prepare { my ($dir, $count); $count = 0; for $dir (<$user{targetdir}/*>) { $count++ if ((-d $dir) && ($dir =~ /$setname/)); } # Only add the $set_count if it's required. The main purpose is to # avoid overwriting older directories. if (-d "$user{targetdir}/$setname") { $set_dir = "$user{targetdir}/$setname-$count"; } else { $set_dir = "$user{targetdir}/$setname"; } if (mkdir($set_dir, 0755)) { mkdir("$set_dir/thumbs", 0755); mkdir("$set_dir/images", 0755); mkdir("$set_dir/originals", 0755); # Are we in slider compat mode? mkdir("$set_dir/$default{sliderdir}",0755) if ($config{slider_compat} == 1); # Make the right subdirs for (0 .. $#rfactors) { my $subdir; $subdir = $_ + 1; mkdir("$set_dir/images/$subdir",0755); } return($set_dir); } else { die "ERROR: Unable to make directory $set_dir\n"; } exit; } # Convert the images and place them in the proper location. Populate the # $images hash with info. sub thumbs_convert_images { my ($count, $num, $file); my ($x, $y, $sizeinfo); $count = 0; print "Converting images "; for $file (<$user{sourcedir}/*>) { # Make sure input files are binary files and populate the # images hash. if (-B $file && -f $file) { $num = $count + 1; $images[$count]{image_num} = $num; # Figure out the size of the image ($x, $y, $sizeinfo) = imgsize($file); if ($x) { $images[$count]{width} = $x; $images[$count]{height} = $y; } else { ### There's a bug in here somewhere but I ### I haven't quite figured out how to fix it ### just yet. Not to worry, it shouldn't be ### easily triggered. print "\nWARN: $file is in unknown format "; undef $images[$count]; next; } # Breakdown file into base and ext parts # This is based on the premise that the original file # is of the form "base.ext" $file =~ /.*\/(.*)\.([a-zA-Z]{3,4})$/; $images[$count]{filename} = "$1.$2"; # Fixup $images[$count]{file_suffix} = $2; $images[$count]{basename} = sprintf("%s_%03d.%s","$setname","$num","$2"); thumbs_convert_image_sizes($images[$count]); ++$count; } } print " Done\n"; } # Convert the image to all the different sizes sub thumbs_convert_image_sizes { my ($image) = @_; my ($rfactor, $count); # Start the counter $count = 1; # Convert to each size. I wish convert was not so fscking slow. for $rfactor (@rfactors) { my ($x, $y); # Figure out using the reduction factor what the final rez is $x = int($image->{width}/$rfactor); $y = int($image->{height}/$rfactor); # Invoke evil system call system("convert $config{convert_xoptions} -geometry ${x}x${y}" . " $user{sourcedir}/$image->{filename} " . "$set_dir/images/$count/$image->{basename}"); $count++; } # Create a thumbnail. Nasty looking system call isn't it? system("convert $config{convert_xoptions} -geometry $user{thumb_size}" . " $user{sourcedir}/$image->{filename} " . "$set_dir/thumbs/$image->{basename}"); # Progress meter =). It's a smiley for dria. print "."; } # Create thumbnail index sub thumbs_create_html_file { my ($date, $count, $num_images, $total_rows, $extra); my ($image_base, $num_left, $td_width, $td_width_extra); my ($i, $j); # grab date, add to heading $date = `date +"%B %e, %Y"`; chomp($date); print "Creating html file "; open(HTML,"> $set_dir/$config{html_filename}") or die("ERROR: Unable to create $set_dir/$config{html_filename}\n"); # Write header information print HTML "\n", "\n\n", "\n", "\t$user{page_heading}\n", "\t\n", "\n\n", "\n\n", "
\n\n"; # Do we want a fancy heading? If so, uppercase $user{page_heading} if ($config{fancy_caption} == 1) { my @caption; my ($string) = uc($user{page_heading}); (@caption) = split(//,$string), print HTML "
", join("    ",@caption), "\n", "


\n"; } else { print HTML "

$user{page_heading}

\n", "$user{page_desc}

\n"; } # Are we in slider compat mode? if ($config{slider_compat} == 1) { print HTML "", "slides

\n"; } print HTML "Clicking thumbnail will view top resolution ", "listed.

\n"; # Set some needed vars $count = 0; $num_images = @images; # Calculate column width $td_width = int(100 / $user{columns}); # Figure out the number of rows needed $total_rows = int($num_images / $user{columns}); $extra = $num_images % $user{columns}; $total_rows++ unless ($extra == 0); # Print some information for script. XML would probably be useful here. # Feel free to suggest formats. print HTML "\n\n", "\n", "\n", "\n", "\n\n"; # Generate tables for images for ($i = 0; $total_rows > $i; $i++) { print HTML "\t\n", "\t\t\n"; $num_left = $num_images - $count; if ($num_left == $extra) { # Incomplete row for ($j = 0; $extra > $j; $j++) { print "."; $td_width_extra = int(100 / $extra); thumbs_create_column($images[$count],$td_width_extra); ++$count; } } else { # Full row for ($j = 0; $user{columns} > $j; $j++) { print "."; thumbs_create_column($images[$count],$td_width); ++$count; } } print HTML "\t\t\n", "\t
\n\n"; } # Write credit info print HTML "

Generated by ", "", "thumbelizer $version"; # Write footer information print HTML "
\n\n", "\n\n", "\n"; close(HTML); print " Done\n"; } # Print out individual columns for html file creation sub thumbs_create_column { my ($image, $td_width) = @_; my ($thumb_width, $thumb_height, $rfactor, $filesize_kb, $count); my ($x, $y); # Get thumb size for html width and height tags to be compliant ($thumb_width, $thumb_height) = ($user{thumb_size} =~ /(\d{1,4})x(\d{1,4})/); $count = 1; # Start the link counter # Print thumb, link to smallest image size print HTML "\t\t

\n", "\t\tImage $image->{image_num}
\n", "\t\t{basename}"; } else { print HTML "images/$count/$image->{basename}"; } print HTML "\">", "{basename}\" ", "width=\"$thumb_width\" height=\"$thumb_height\" ", "alt=\"image $image->{image_num}\" border=1>", "
\n", "\t\t\n"; # Go through and print link to each size for $rfactor (@rfactors) { my $file; $file = "$count/$image->{basename}"; # Figure out the filesize and convert to kb from bytes $filesize_kb = int((-s "$set_dir/images/$file") / 1024); # Figure out the dimensions of the image ($x, $y) = imgsize("$set_dir/images/$file"); # Print the HTML fragment print HTML "\t\t", "${x}x${y} ($filesize_kb kb)
\n"; $count++; } # Create a link for the original image too $filesize_kb = int((-s "$user{sourcedir}/$image->{filename}") / 1024); # Decide if we want to rename the originals if ($config{keep_filename} == 0) { print HTML "\t\t{basename}\">", "original ($filesize_kb kb)
\n"; } else { print HTML "\t\t{filename}\">", "original ($filesize_kb kb)
\n"; } print HTML "\t\t
\n", "\t\t\n"; } # Copies the original images to $set_dir/originals. Rename if necessary. sub thumbs_originals_copy { my $count = 0; print "Copying originals to $set_dir/originals "; for (<$user{sourcedir}/*>) { # Move binary files, adjust test to fit if (-B $_ && -f $_) { # Decide if we want to rename the originals if ($config{keep_filename} == 0) { my $image; # Select the right file to reference $image = $images[$count]; cp("$_","$set_dir/originals/" . "$image->{basename}"); } else { cp("$_","$set_dir/originals"); } $count++; print "."; } } print " Done\n"; } # Print program usage sub thumbs_usage { print "Usage: thumbelizer [OPTION]\n\n", "\t-i, --interactive\tsome config settings prompted\n", "\t-d, --default\t\tdefault mode, uses defaults within file\n", "\t-h, --help\t\tdisplay help (this menu) and exit\n", "\t-v, --version\t\toutput version and exit\n\n"; } # Print program name and version number sub thumbs_version { print "thumbelizer $version\n"; } sub thumbs_option_check { # Make sure we are passed decent arguments unless ($#ARGV == 0) { thumbs_usage; exit; } $_ = $ARGV[0]; if (/^-{1,2}i/) { $mode_interactive = 1; } elsif (/^-{1,2}d/) { $mode_interactive = 0; } elsif (/^-{1,2}v/) { thumbs_version; exit; } else { thumbs_usage; exit; } }