#!/usr/bin/env perl # eSlides 2.0 # Copyright (C) 2004 Edmond Lau , # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Date Created: June 29, 2004 # Date Upgraded to Version 2.0: May 25, 2005 # Website: # http://web.mit.edu/edmond/www/eSlides.html # Usage: # eSlides [-tar] [-shadow] input-dir "title" # print copyright information print "Version: eSlides 2.0 05/16/05 http://web.mit.edu/edmond/www/eSlides.html\n"; print "Copyright (C) 2004 Edmond Lau\n\n"; # program path information my $path = substr($0, 0, rindex($0, "/")); # get the path used to execute the program my $CSS = "$path/eSlides.css"; my $JS = "$path/eSlides.js"; my $HTML = "$path/eSlides.template"; # program information my $THUMBNAIL_WIDTH = 160; #120; my $THUMBNAIL_HEIGHT = 120; #160; my $SLIDE_WIDTH = 175; #135; # css layout information my $FILMSTRIP_BORDER = 30; my $FILMSTRIP_WIDTH = 5 * $SLIDE_WIDTH; my $CELL_HEIGHT = $THUMBNAIL_HEIGHT + 14 + 3; # the plus 3 is a fix for IE bug my $BODY_WIDTH = $FILMSTRIP_WIDTH + 2 * $FILMSTRIP_BORDER; my $IMAGE_WIDTH = $THUMBNAIL_WIDTH + 2; my $IMAGE_HEIGHT = $THUMBNAIL_HEIGHT + 2; my $INFO_TOP = $CELL_HEIGHT/2 - $THUMBNAIL_HEIGHT/8; my $ZIP_TOP = $CELL_HEIGHT + 75; my $ZIP_LEFT = $FILMSTRIP_WIDTH - 55; my $SPOTLIGHT_WIDTH = 600; # html layout information my $LEFT_NAVLINK_LOC = 90; my $RIGHT_NAVLINK_LOC = $SLIDE_WIDTH * 5 - 75; # program parameters my $tar = 0; my $shadow = 0; my $input_dir; my $title; # check command line args if(@ARGV == 2) { ($input_dir, $title) = @ARGV[0, 1]; } elsif (@ARGV == 3) { my $flag; ($flag, $input_dir, $title) = @ARGV[0..2]; if ($flag eq "-tar") { $tar = 1; } elsif ($flag eq "-shadow") { $shadow = 1; } else { print "Unrecognized option: ", $flag, "\n"; usage(); } } elsif (@ARGV == 4) { my $flag1, $flag2; ($flag1, $flag2, $input_dir, $title) = @ARGV[0..3]; if ($flag1 eq "-tar") { $tar = 1; } elsif ($flag1 eq "-shadow") { $shadow = 1; } else { print "Unrecognized option: ", $flag1, "\n"; usage(); } if ($flag2 eq "-tar") { $tar = 1; } elsif ($flag2 eq "-shadow") { $shadow = 1; } else { print "Unrecognized option: ", $flag2, "\n"; usage(); } } else { usage(); } # strip front and trailing whitespace from $title =~ s/(^\s*)|(\s*$)//g; # regex output directory $output_dir = $title; # strip all non-alphanumeric characters $output_dir =~ s/[^\w\s-]//g; # replace all whitespace groups with dashes $output_dir =~ s/\s+/-/g; # open the input directory opendir(INDIR, $input_dir) or die "Can't open directory $input_dir"; # strip any trailing slash from the input directory $input_dir =~ s/\/$//; # build an array of the input directory's images my @images; while (my $file = readdir(INDIR)) { #print "Reading file $file...\n"; if ($file =~ /(\.jpeg|\.jpg)$/i) { # print "$file...\n"; push (@images, $file); } } my $total_images = @images; print "$total_images images found in $input_dir\n"; closedir(INDIR) or die "Can't close directory $input_dir"; # create the output directory, with all-read-read permissions mkdir($output_dir, 0744) or die "Can't make directory $output_dir"; # create thumbnail directory mkdir("$output_dir/thumbnails", 0744) or die "Can't make directory $output_dir/thumbnails"; # create images directory mkdir("$output_dir/images", 0744) or die "Can't make directory $output_dir/images"; # generate thumbnails to output_dir/thumbnails/ print "Generating thumbnails...\n"; foreach(@images) { # resize image in input_dir/ to at most THUBMNAIL_WIDTHxTHUMBNAIL_HEIGHT in output_dir/thumbnails/ # convert will shrink image enough to fit within THUMBNAIL_WIDTHxTHUMBNAIL_HEIGHT bounding box my @args = ("-size", # optimization: give hint to ImageMagick about thumbnail size "${THUMBNAIL_WIDTH}x${THUMBNAIL_HEIGHT}", "$input_dir/$_", # input image "-thumbnail", # thumbnail size, also strips profiles and comments "${THUMBNAIL_WIDTH}x${THUMBNAIL_HEIGHT}", "$output_dir/thumbnails/$_"); # output image print "convert @args\n"; system("convert", @args); # == 0 or cleanup("ImageMagick error while running convert") ; } # gather image info # remember image orientations and thumbnail heights my %images_info; print "Scanning images...\n"; foreach(@images) { # get the current size of the image my($width, $height) = get_dimensions("$output_dir/thumbnails/$_"); $images_info{"$_"."h"} = $height; $images_info{"$_"."w"} = $width; if ($width > $height) { $images_info{"$_"."o"} = 'horizontal_slide'; } else { $images_info{"$_"."o"} = 'vertical_slide'; } } # add drop shadows to thumbnails if ($shadow) { print "Adding drop shadows to thumbnails...\n"; foreach(@images) { add_drop_shadow("$output_dir/thumbnails/$_", $images_info{"$_"."w"}, $images_info{"$_"."h"}); } } # generate spotlight images to output_dir/images/ print "Generating viewing images...\n"; foreach(@images) { my $thumbnail_width = $images_info{"$_"."w"}; my $thumbnail_height = $images_info{"$_"."h"}; my $scaled_height = $thumbnail_height * $SPOTLIGHT_WIDTH/$thumbnail_width; # my $scaling_factor = $width/$SPOTLIGHT_WIDTH; # my $scaled_height = $height/$scaling_factor; # resize image in input_dir/ to SPOTLIGHT_WIDTH in output_dir/images/ directory my @args = ("-size", # optimization: give hint to ImageMagick about thumbnail size "${SPOTLIGHT_WIDTH}x${scaled_height}", "$input_dir/$_", # input image "-scale", # scaled size "${SPOTLIGHT_WIDTH}x${scaled_height}", "$output_dir/images/$_"); # output image print "convert @args\n"; system("convert", @args); # == 0 or cleanup("ImageMagick error while running convert"); } # tar up the images? my $tar_filename; if ($tar) { # tar up the images into a .tar file with the output_dir as the filename $tar_filename = "$output_dir.tar"; print "Tarring images in $input_dir to $tar_filename...\n"; # in order to create a tar file output/sexy_edmond.tar of all images under input/images/, # we need to run the command: # tar -cf output/sexy_edmond.tar -C input images # the -C option changes to the input directory before tarring. If not for the -C option, # then the tar file will include the input/images directory structure within the tar # file, rather than just having an images directory. # therefore, if necessary change directory to the one containing the target folder of images # ex: if input_dir = vacation/pictures/edmond, change the directory to vacation/pictures # ex: if input_dir = pictures, stay in same directory # note that input_dir's trailing slash has already been stripped my $last_slash_index = rindex($input_dir, "/"); my @args; if ($last_slash_index != -1) { my $path = substr($input_dir, 0, $last_slash_index); my $target_dir = substr($input_dir, $last_slash_index+1); @args = ("-cf", "$output_dir/$tar_filename", "-C", "$path", "$target_dir"); } else { @args = ("-cf", "$output_dir/$tar_filename", "$input_dir"); } # tar up the files print "tar @args\n"; system("tar", @args); } # generate the html print "Generating $output_dir/index.html...\n"; generateHTML("$output_dir/index.html", $title); # generate the css print "Generating $output_dir/eSlides.css...\n"; generateCSS("$output_dir/eSlides.css"); # generate the javascript print "Generating $output_dir/eSlides.js...\n"; generateJS("$output_dir/eSlides.js"); sub usage { print "Correct usage: "; print "eSlides [-tar] [-shadow] input-dir \"title\"\n"; die "\n"; } sub cleanup { my $msg = shift; system "rm -r $output_dir"; die $msg; } sub get_dimensions { my $image = shift; $command = "identify $image"; print "$command\n"; my $output = `$command`; my($width, $height) = ($output =~ /(\d+)x(\d+)/); return ($width, $height); } # adapted from Brendt Wohlberg's dropshadow script # http://www.wohlberg.net/public/software/photo/dropshadow/ sub add_drop_shadow { my ($image, $width, $height) = @_; # my $border = 8; # my $gap = 4; # my $blur = "3.3x2" ; # my $shoulder = 4; my $border = 4; my $gap = 2; my $blur = "1.7x1" ; my $shoulder = 2; @args = ("-bordercolor", # add a white border "white", "-border", # border size "${border}x${border}", "-chop", # chop of border # of rows and cols from upper left "${border}x${border}", "-page", # adjust the canvas size "${border}x${border}+0+0", "$image"); print "mogrify @args\n"; system("mogrify", @args); @args = ("-fill", # fill the subsequent rectangles "grey50", "-draw", # draw the vertical rectangle on the right side "'rectangle $width,$shoulder ".($width+$border-$gap).",".($height+$border-$gap)."'", "-draw", # draw the horizontal rectangle on the bottom "'rectangle $shoulder,$height ".($width+$border-$gap).",".($height+$border-$gap)."'", "$image"); print "mogrify @args\n"; system("mogrify @args"); @args = ("-region", "${border}x".($height+$border)."+$width", "-blur", "$blur", "$image"); print "mogrify @args\n"; system("mogrify", @args); @args = ("-region", "${width}x${border}+0+${height}", "-blur", "$blur", "$image"); print "mogrify @args\n"; system("mogrify", @args); } sub generateHTML { my($html_filename, $title) = @_; # open the input and output files open(HTML_OUT, "> $html_filename"); open(HTML_IN, "$HTML"); # build a string for all the slides my $slides_list; my $i = 1; foreach(@images) { #my($width, $height) = get_dimensions("$output_dir/thumbnails/$_"); # determine if the image is horizontal or vertical my $class = $images_info{"$_"."o"}; my $height = $images_info{"$_"."h"}; #if ($width > $height) { # $class = "horizontal_slide"; #} else { # $class = "vertical_slide"; #} my $vertical_offset = ($THUMBNAIL_HEIGHT - $height)/2; # generate HTML-safe filenames $html_filename = $_; $html_filename =~ s/\s/%20/g; # generate the list of slides my $image_loc = ($i+1) * $SLIDE_WIDTH; $slides_list .= qq| <span id="slide_$i" class="$class" style="left: ${image_loc}px;">\n|; $slides_list .= qq| <img id="thumbnail_$i" src="thumbnails/$html_filename" style="top: ${vertical_offset}px;" onclick="select($i)" alt="slide $i" />\n|; $slides_list .= " </span>\n"; $i++; } my $tar_link; if($tar) { $tar_link .= qq| <div class="zip">\n|; $tar_link .= qq|<a href="$tar_filename">[download all images]</a>\n|; $tar_link .= " </div>"; } # get the current time my $time = getFormattedTime(); my $total_images = $i-1; # for each line in the html template # if there is no $, output as is # otherwise, replace with appropriate text while(<HTML_IN>) { if (!m"\$") { print HTML_OUT $_; } else { s|\$TITLE|$title|; s|\$LEFT_NAVLINK_LOC|$LEFT_NAVLINK_LOC|; s|\$RIGHT_NAVLINK_LOC|$RIGHT_NAVLINK_LOC|; s|\$TAR_LINK|$tar_link|; s|\$SLIDES_LIST|$slides_list|; s|\$TOTAL_IMAGES|$total_images|; s|\$CREATION_DATE|$time|; s|\$SPOTLIGHT_IMAGE|images/$images[0]|; print HTML_OUT $_; } } close(HTML_OUT) or die "Can't close $html_filname"; close(HTML_IN) or die "Can't close $HTML"; } sub generateCSS { my $css_filename = shift; # open the input and output files open(CSS_OUT, "> $css_filename"); open(CSS_IN, "$CSS"); my $image_border = ""; if (!$shadow) { $image_border = "border: 1px solid black;\n"; } # for each line in the css template # if there is no $, output as is # otherwise, replace with appropriate text while (<CSS_IN>) { if (!m"\$") { # no $, so output line as is print CSS_OUT $_; } else { # replace the $ variable with the appropriate value s|\$BODY_WIDTH|$BODY_WIDTH|; s|\$FILMSTRIP_BORDER|$FILMSTRIP_BORDER|g; s|\$FILMSTRIP_WIDTH|$FILMSTRIP_WIDTH|; s|\$INFO_TOP|$INFO_TOP|; s|\$CELL_HEIGHT|$CELL_HEIGHT|; s|\$IMAGE_WIDTH|$IMAGE_WIDTH|; s|\$IMAGE_HEIGHT|$IMAGE_HEIGHT|; s|\$IMAGE_BORDER|$image_border|; s|\$ZIP_LEFT|$ZIP_LEFT|; s|\$ZIP_TOP|$ZIP_TOP|; s|\$SPOTLIGHT_WIDTH|$SPOTLIGHT_WIDTH|; print CSS_OUT $_; } } close(CSS_OUT) or die "Can't close $css_filename"; close(CSS_IN) or die "Can't close $CSS"; } sub generateJS { my $js_filename = shift; # open the input and output files open(JS_OUT, "> $js_filename"); open(JS_IN, "$JS"); # build a string for the javascript array of images # note that perl arrays are zero-based, but my java-array is 1-based my $image_array; my $i = 1; foreach(@images) { $image_array .= "images[$i] = \"".$_."\";\n"; $i++; } # for each line in the javascript template # if there is no $, output as is # otherwise, replace with appropriate text while (<JS_IN>) { if (!m"\$") { # no $, so output line as is print JS_OUT $_; } else { # replace the $ variable with the appropriate value s|\$IMAGE_ARRAY|$image_array|; s|\$SLIDE_WIDTH|$SLIDE_WIDTH|; s|\$TOTAL_IMAGES|$total_images|; print JS_OUT $_; } } close(JS_OUT) or die "Can't close $jss_filename"; close(JS_IN) or die "Can't close $JS"; } sub getFormattedTime() { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); my $am_pm; if ($hour >= 12) { # 23:00 is 11PM # 12:00 is 12PM $am_pm = "PM"; if ($hour > 12) { $hour -= 12; } } else { $am_pm = "AM"; if ($hour == 0) { $hour = 12; } } my $time = sprintf("%s %s, %d, %02d:%02d%s", $abbr[$mon], $mday, $year + 1900, $hour, $min, $am_pm); return $time; }