#! /bin/sh # This script creates tumbnails, reduced versions of large images, and an # index.html file pointing to all of it. GLOBAL_rcsid='$Id: makethumbs.sh,v 1.152 2002/01/24 05:27:41 molenda Exp $' GLOBAL_rcsrev='$Revision: 1.152 $' # Design goals are # (1) exist in a single script that can be mailed around easily, etc. # (2) generate clean, simple, portable HTML # (3) no databases required # (4) portable portable portable # There are many other programs that compromise some or all of these goals. # They are real neat, they make great web pages, they organize your life. # They don't fit in a single ugly Bourne shell script whose only point in # life is to take pictures off your digital camera and make them basically # presentable to your friends. # This script is in the public domain, share and enjoy. # The latest version is always at http://www.molenda.com/makethumbs/ # Written by Jason Molenda, 1998-09-13; rewritten less lamely 2001-10-26. ## Notes to people reading this script. ## ## Start at main() and trace the function calls from there. ## As much as I like Bourne shell, I should have just done this in ## perl or python. On the down side, whichever of those I pick, I'll ## hear constant whining from about half of my friends. No one likes ## Bourne shell, so it's the safest language choice. And to be honest, ## I sometimes think it's too easy when you have all those fancy high ## level data types, scoping, abstractions, and regular expression at your ## finger tips -- it's a little more fun when you need to work hard to ## make things work right. ## Return values from functions are prefixed with "RETURN_". ## Command line options are prefixed with "ARGV_". ## Defaults are prefixed with "DEFAULT_" ## Settings from the .makethumbsrc are prefixed with "DOTRC_" ## Globals variables are prefixed with "GLOBAL_". ## GLOBAL_ will hold all the settings that we should act on. These came ## either from a DEFAULT_, ARGV_, or DOTRC_ if the user overrode the DEFAULT_. main () { find_necessary find_optional init_defaults read_dotrc_file make_dir_transversible "." parse_args $* get_image_list create_descriptions_file point_stdout_to_index_file progress_update_start_creating_index_html [ $GLOBAL_print_html_header_footer -eq 1 ] && print_html_header print_html_table_start iterate_over_image_list print_html_table_end [ $GLOBAL_print_html_header_footer -eq 1 ] && print_html_footer progress_update_done_creating_index_html [ $GLOBAL_create_slideshow -eq 1 ] && create_slideshow exit 0 } # DEFAULT_ values are treated as const and are not normally referenced # by functions in this script. Functions should refer to the GLOBAL_ # version -- it will either be set to the DEFAULT_ or to the ARGV_ value # if the user overrides it on the cmd line. init_defaults () { TMPDIR=${TMPDIR-/tmp} DEFAULT_columns=3 DEFAULT_max_thumb_size=150 DEFAULT_use_two_windows=0 DEFAULT_reduce_big_pics=1 DEFAULT_reduce_trigger_height=768 DEFAULT_reduce_trigger_width=1024 DEFAULT_reduce_height=480 DEFAULT_reduce_width=640 DEFAULT_remove_originals=0 DEFAULT_create_slideshow=1 DEFAULT_rotation_filename="rot-state.txt" DEFAULT_show_progress=1 DEFAULT_body_tag="" DEFAULT_meta_tag="undef" DEFAULT_html_charset="undef" DEFAULT_index_filename="index.html" DEFAULT_index_hrefname="index.html" DEFAULT_print_captions=1 DEFAULT_compact_index_page=0 DEFAULT_descriptions_filename="descriptions.txt" DEFAULT_compression_level="75" DEFAULT_image_subtitle_text="undef" DEFAULT_footer_text="undef" DEFAULT_usa_specific_date_format_checks=1 DEFAULT_slideshow_previous_pre_link="

[" DEFAULT_slideshow_previous="previous" DEFAULT_slideshow_previous_post_link="]

" DEFAULT_slideshow_next_pre_link="

[" DEFAULT_slideshow_next="next" DEFAULT_slideshow_next_post_link="]

" DEFAULT_slideshow_ret_to_index_pre_link="

[" DEFAULT_slideshow_ret_to_index="index" DEFAULT_slideshow_ret_to_index_post_link="]

" GLOBAL_columns=$DEFAULT_columns GLOBAL_max_thumb_size=$DEFAULT_max_thumb_size GLOBAL_use_two_windows=$DEFAULT_use_two_windows GLOBAL_reduce_big_pics=$DEFAULT_reduce_big_pics GLOBAL_reduce_trigger_height=$DEFAULT_reduce_trigger_height GLOBAL_reduce_trigger_width=$DEFAULT_reduce_trigger_width GLOBAL_reduce_height=$DEFAULT_reduce_height GLOBAL_create_slideshow=$DEFAULT_create_slideshow GLOBAL_reduce_width=$DEFAULT_reduce_width GLOBAL_rotation_filename=$DEFAULT_rotation_filename GLOBAL_show_progress=$DEFAULT_show_progress GLOBAL_remove_originals=$DEFAULT_remove_originals GLOBAL_body_tag=$DEFAULT_body_tag GLOBAL_meta_tag=$DEFAULT_meta_tag GLOBAL_html_charset=$DEFAULT_html_charset GLOBAL_index_filename=$DEFAULT_index_filename GLOBAL_index_hrefname=$DEFAULT_index_hrefname GLOBAL_print_captions=$DEFAULT_print_captions GLOBAL_compact_index_page=$DEFAULT_compact_index_page GLOBAL_descriptions_filename=$DEFAULT_descriptions_filename GLOBAL_compression_level=$DEFAULT_compression_level GLOBAL_image_subtitle_text=$DEFAULT_image_subtitle_text GLOBAL_footer_text=$DEFAULT_footer_text GLOBAL_usa_specific_date_format_checks=$DEFAULT_usa_specific_date_format_checks GLOBAL_slideshow_previous_pre_link=$DEFAULT_slideshow_previous_pre_link GLOBAL_slideshow_previous=$DEFAULT_slideshow_previous GLOBAL_slideshow_previous_post_link=$DEFAULT_slideshow_previous_post_link GLOBAL_slideshow_next_pre_link=$DEFAULT_slideshow_next_pre_link GLOBAL_slideshow_next=$DEFAULT_slideshow_next GLOBAL_slideshow_next_post_link=$DEFAULT_slideshow_next_post_link GLOBAL_slideshow_ret_to_index_pre_link=$DEFAULT_slideshow_ret_to_index_pre_link GLOBAL_slideshow_ret_to_index=$DEFAULT_slideshow_ret_to_index GLOBAL_slideshow_ret_to_index_post_link=$DEFAULT_slideshow_ret_to_index_post_link GLOBAL_stdout_has_been_redirected=0 GLOBAL_descriptions_filename_validated=0 GLOBAL_descriptions_filename_is_invalid=0 GLOBAL_already_failed_guessing_date_from_dir=0 GLOBAL_makethumbs_version=`echo "$GLOBAL_rcsrev" | sed 's,[^0-9.],,g'` GLOBAL_rcsid=`echo "$GLOBAL_rcsid" | sed -e 's,\$Id: ,,' -e 's,molenda Exp.*,,'` # OBSOLETE: Remove these two after a few more revisions 2001-12-27 GLOBAL_max_thumb_height=0 GLOBAL_max_thumb_width=0 } parse_args () { local optname optarg while [ $# -gt 0 ] do optname="`echo $1 | sed 's,=.*,,'`" optarg="`echo $1 | sed 's,^[^=]*=,,'`" case "$1" in --maxthumbsize=* | --max-thumb-size=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_max_thumb_size=$optarg GLOBAL_max_thumb_size=$ARGV_max_thumb_size ;; --columns=* | --cols=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_columns=$optarg GLOBAL_columns=$optarg ;; --use-two-windows*|--enable-two-windows|--with-two-windows) ARGV_use_two_windows=1 GLOBAL_use_two_windows=$ARGV_use_two_windows ;; --remove-orig*) ARGV_remove_originals=1 GLOBAL_remove_originals=$ARGV_remove_originals ;; --progress) ARGV_show_progress=1 GLOBAL_show_progress=$ARGV_show_progress ;; --quiet | -q) ARGV_show_progress=0 GLOBAL_show_progress=$ARGV_show_progress ;; --disable-reduce|--without-reduce) ARGV_reduce_big_pics=0 GLOBAL_reduce_big_pics=$ARGV_reduce_big_pics ;; --disable-slideshow|--without-slideshow) ARGV_create_slideshow=0 GLOBAL_create_slideshow=$ARGV_create_slideshow ;; --enable-reduce|--with-reduce) ARGV_reduce_big_pics=1 GLOBAL_reduce_big_pics=$ARGV_reduce_big_pics ;; --compact-index|--compact) ARGV_compact_index_page=1 GLOBAL_compact_index_page=$ARGV_compact_index_page ;; --reduce-height=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_reduce_height=$optarg GLOBAL_reduce_height=$ARGV_reduce_height ;; --reduce-width=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_reduce_width=$optarg GLOBAL_reduce_width=$ARGV_reduce_width ;; --reduce-trigger-height=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_reduce_trigger_height=$optarg GLOBAL_reduce_trigger_height=$ARGV_reduce_trigger_height ;; --reduce-trigger-width=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_reduce_trigger_width=$optarg GLOBAL_reduce_trigger_width=$ARGV_reduce_trigger_width ;; --compression-level=*|--compression=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_compression_level=$optarg GLOBAL_compression_level=$ARGV_compression_level ;; -h | --help | -v | --version | -V) help exit 1 ;; -*) echo "`basename $0`: ERROR: Unrecognized option \"$1\"" >&2 ;; *) ARGV_image_list="$ARGV_image_list $1" ;; esac shift done if [ -n "$ARGV_compact_index_page" ] then enable_compact_index_mode fi } help () { # The following exec goop so I don't have to manually redirect every # message to stderr in this function. exec 4>&1 # save stdout fd to fd #4 exec 1>&2 # redirect stdout to stderr cat <<__EOM__ Usage: `basename $0` [options] --compact-index Create a compact index page to pack in lots of thumbnails --maxthumbsize=n Maximum size of thumbnails, in pixels, default $DEFAULT_max_thumb_size --columns=n Number of thumbnails per line, default $DEFAULT_columns --disable-reduce Don't create a reduced image if the picture is large --disable-slideshow Don't create slideshow files --compression=n Set JPEG compression percentage to n for generated images. Default is 75. Things usually look OK down to the 40-50's. --use-two-windows Bring up a new window to see images, default is `[ $DEFAULT_use_two_windows -eq 1 ] && echo enabled || echo disabled` __EOM__ if [ $DEFAULT_show_progress -eq 1 ] then echo '--quiet Avoid unnecessary output while running' else echo '--progress Show progress updates as the script runs' fi cat <<__EOM__ --remove-originals Remove original images if we make reduced versions. Useful when disk space is limited; default is `[ $DEFAULT_remove_originals -eq 1 ] && echo enabled || echo disabled` WARNING!!! This option *will* remove your original images if reduced images are available! Run this script in a directory of JPEG files to create thumbnail images and an ${GLOBAL_index_filename}. If an ${GLOBAL_index_filename} is already present, its HTML is sent to stdout. Makethumbs will not overwrite files you've created by hand. Makethumbs will not modify your original images. Makethumbs will not corrupt your precious bodily fluids. You may list the JPEG files on the command line if you prefer. By default, `basename $0` works on every JPEG file in the current working directory. You can permanently override options by creating a ~/.makethumbsrc file. Many more features can be tweaked via the .makethumbsrc file. See the documentation on the makethumbs home page for more information. This script written by Jason Molenda, makethumbs(AT)molenda.com. This is version ${GLOBAL_makethumbs_version}. The latest version of this script is always available at http://www.molenda.com/makethumbs/ __EOM__ exec 1>&4 # Copy stdout fd back from temporary save fd, #4 } # RETURN_found is 1 if found, 0 if not found. If found, $RETURN_fullname # contains the path + filename. find_in_path () { local OFS i target dir target="$*" RETURN_fullname="" RETURN_found=0 OFS="$IFS" IFS=: for i in $PATH do [ -z "$i" ] && i="." if [ -f "$i/$target" ] then RETURN_fullname="$i/$target" RETURN_found=1 break fi done IFS="$OFS" } # Compact Index Mode is a special case because the setting of this # one mode involves setting several other variables, unless the # user has explicitly overridden them elsewhere. enable_compact_index_mode () { [ $GLOBAL_compact_index_page -eq 0 ] && return if [ -z "$ARGV_max_thumb_size" -a -z "$DOTRC_max_thumb_size" ] then GLOBAL_max_thumb_size=75 fi if [ -z "$ARGV_print_captions" -a -z "$DOTRC_print_captions" ] then GLOBAL_print_captions=0 fi if [ -z "$ARGV_columns" -a -z "$DOTRC_columns" ] then GLOBAL_columns=6 fi } # Parse a user's $HOME/.makethumbsrc. The code here is kind of # funky because I didn't want to just bourne-shell source the file # (". $HOME/.makethumbsrc"); any syntax error in that startup file # would have caused makethumbs to fail in weird ways and users could have # trouble debugging it. It's a huge amount of work to get all the parsing # correct so spaces, quote marks, apostrophies, etc., are all carried over # accurately. The sed expression where $value gets set is not something # I'm too proud of - this is always the sort of thing that is tricky in # Bourne shell. read_dotrc_file () { local this_dotrc tmpf varname varname_is_valid line value curval for this_dotrc in $HOME/.makethumbsrc $HOME/.makethumbs $HOME/makethumbsrc \ .makethumbsrc .makethumbs makethumbsrc do [ ! -f "$this_dotrc" ] && continue make_tmpfile dotrc tmpf=$RETURN_tmpfile add_cleanup $tmpf cat "$this_dotrc" | grep -v '^[ ]*#' | grep = > $tmpf [ ! -s $tmpf ] && continue while read line do varname_is_valid=0 varname=`echo "$line" | sed -e 's,=.*,,' -e 's,[^A-Za-z_0-9],,g' \ -e 's,^ARGV_,,' -e 's,^GLOBAL_,,' \ -e 's,^DEFAULT_,,' -e 's,^DOTRC_,,'` # Eliminate whitespace, quotes around the value value=`echo "$line" | sed -e 's,^[^=]*=,,' -e 's,^[ ]*,,' \ -e 's,[ ]*$,,' \ -e s,^\[\"\'\]\[\ \ \]\*,, \ -e s,\[\ \ \]\*\[\"\'\]\$,,` if echo "$varname" | grep -i '_FILE$' >/dev/null 2>&1 then read_in_file_contents "$value" if [ $RETURN_file_found -eq 1 ] then value=`echo "$RETURN_file_contents" | grep -v '^[ ]*$'` else echo WARNING: Unable to read in file "$value" for variable "$varname" 2>&1 continue fi varname=`echo "$varname" | sed 's,_[Ff][Ii][Ll][Ee]$,,'` fi eval [ -n \"\$GLOBAL_$varname\" ] && varname_is_valid=1 if [ $varname_is_valid -eq 0 ] then echo ERROR: "$this_dotrc" has unrecognized variable name, \"$varname\"!>&2 continue fi # Try to do a little verification if the current value is numeric. I could # probably add some extra checks if the current val is 0 or 1, making an # assumption that it's a boolean value. (someone might try to use "yes" # instead of '1', for instance) curval=`eval echo \\$GLOBAL_$varname` if echo "$curval" | grep '^[0-9]*$' >/dev/null 2>&1 then if [ -z "$value" ] then echo WARNING: Variable $varname currently has a numeric value of $curval >&2 echo WARNING: but you\'re setting it to an empty value. >&2 else if echo "$value" | grep '^[0-9]*$' >/dev/null 2>&1 then : else echo WARNING: Variable $varname currently has a numeric value of $curval >&2 echo WARNING: but you\'re setting it to \"$value\". >&2 fi fi fi eval DOTRC_$varname='$value' eval GLOBAL_$varname=\$DOTRC_$varname done < $tmpf done # If a user sets some variables, others should be set as well. if [ -n "$DOTRC_compact_index_page" ] then enable_compact_index_mode fi } # A variable might be a filename instead of a value. This function # checks to see if such a file exists and returns the fully qualified # pathname if it does. read_in_file_contents () { local fn i RETURN_file_found=0 RETURN_file_contents="" fn="$*" # Try to expand these via eval if echo "$fn" | egrep '^(~|[$]HOME)' >/dev/null 2>&1 then fn=`eval echo "$fn"` fi # Not all Bourne shells will expand tilde. if echo "$fn" | egrep '^~/' >/dev/null 2>&1 then fn=`echo "$fn" | sed 's,~/,,'` fi if [ -f "$fn" ] then RETURN_file_found=1 RETURN_file_contents=`cat "$fn"` return fi for i in . $HOME .. do if [ -f "$i/$fn" ] then RETURN_file_found=1 RETURN_file_contents=`cat "$i/$fn"` return fi done } # Returns a temp file in $RETURN_tmpfile. # Takes an optional description name argument. make_tmpfile () { local base_tmpfile n if [ $GLOBAL_mktemp_is_present -eq 1 ] then RETURN_tmpfile=`mktemp -q "$TMPDIR/makethumbs-$1.XXXXXXX"` if [ $? -eq 0 ] then return 0 fi fi base_tmpfile="$TMPDIR/makethumbs-$1.$$" RETURN_tmpfile="$base_tmpfile" n=0 while [ -f "$RETURN_tmpfile" ] do n=`expr $n + 1` RETURN_tmpfile="${base_tmpfile}-$n" done return 0 } # Ends program execution if a necessary program is missing. find_necessary () { local missed_something progname missed_something=0 for progname in djpeg cjpeg pnmscale do find_in_path $progname if [ $RETURN_found -eq 0 ] then missed_something=1 echo ERROR: Missing \"$progname\"! >&2 if [ $progname = djpeg -o $progname = cjpeg ] then echo ERROR: You may be able to find a copy of this at ftp://ftp.uu.net/graphics/jpeg >&2 fi if [ $progname = pnmscale ] then echo ERROR: You need to install the \"netpbm\" utilities. >&2 echo ERROR: You can find this at http://netpbm.sourceforge.net/ >&2 fi fi done if [ $missed_something -eq 1 ] then echo "" >&2 echo ERROR: You will find all the necessary utilities pre-installed >&2 echo ERROR: on most Linux systems. >&2 exit 1 fi } # Detect some optional helper programs and remember their presence. find_optional () { local prog varname for prog in metacam jhead dphotox dump-exif rdjpgcom jpegtopnm \ mogrify mktemp do varname=`echo $prog | tr -d '-'` find_in_path $prog if [ $RETURN_found -eq 1 ] then eval GLOBAL_${varname}_is_present=1 else eval GLOBAL_${varname}_is_present=0 fi done } update_cleanups () { trap "rm -f $GLOBAL_cleanuplist; exit 1" 0 1 2 15 } add_cleanup () { GLOBAL_cleanuplist="$GLOBAL_cleanuplist $*" update_cleanups } remove_cleanup () { local fn fn="$*" GLOBAL_cleanuplist=`echo $GLOBAL_cleanuplist | sed "s|${fn}||"` update_cleanups } # Only accepts *one* argument, which may contain space chars. make_file_readable () { if [ -f "$*" ] then chmod a+r "$*" chmod a-x "$*" fi } # Only accepts *one* argument, which may contain space chars. make_dir_transversible () { if [ -d "$*" ] then chmod a+x "$*" fi } exit_if_empty () { local desc val desc="$1" shift val="$*" if [ -z "$val" ] then echo ERROR: No argument given with \"$desc\" command line argument! >&2 exit 1 fi } # Sets file at $GLOBAL_image_list_tmpfile with images to process. # Tries to normalize filename extensions. get_image_list () { local prelim_image_tmpfile i normalized_filename filename make_tmpfile first-image-list prelim_image_tmpfile="$RETURN_tmpfile" make_tmpfile image-list GLOBAL_image_list_tmpfile="$RETURN_tmpfile" add_cleanup "$prelim_image_tmpfile" "$GLOBAL_image_list_tmpfile" if [ -n "$ARGV_image_list" ] then for i in $ARGV_image_list do echo $ARGV_image_list >> $prelim_image_tmpfile done else ls -1 | egrep -i '\.jpg$|\.jpeg$|\.png$|\.gif$' > $prelim_image_tmpfile fi cat $prelim_image_tmpfile | while read filename do [ -s "$filename" ] || continue if echo "$filename" | egrep -- '-t\.|-r\.|-l\.' >/dev/null 2>&1 then continue fi normalized_filename=`echo "$filename" | sed -e 's,.JPG$,.jpg,' -e 's,.jpeg$,.jpg,' -e 's,.JPEG$,.jpg,' \ -e 's,.PNG$,.png,' -e 's,.GIF$,.gif,'` if [ ! -f "$normalized_filename" -a -n "$normalized_filename" ] then if mv "$filename" "$normalized_filename" then filename="$normalized_filename" fi fi #FIXME: This will probably fail on a MacOS HFS+ type system where testing # for "foo.JPG" and "foo.jpg" may both return true if one of the names # is present... Maybe check inode #s or something to be sure. if [ "$filename" != "$normalized_filename" -a \ -f "$filename" -a -f "$normalized_filename" ] then echo "WARNING: Both $filename and $normalized_filename exist, and this script does" 1>&2 echo " odd things when this happens!" 1>&2 fi make_file_readable "$filename" echo "$filename" >> $GLOBAL_image_list_tmpfile done if [ ! -s "$GLOBAL_image_list_tmpfile" ] then echo ERROR: No images found! >&2 exit 1 fi } point_stdout_to_index_file () { if [ -n "$ARGV_image_list" ] then GLOBAL_print_html_header_footer=0 else GLOBAL_print_html_header_footer=1 if [ -f "$GLOBAL_index_filename" ] then remove_file_if_unmodified "$GLOBAL_index_filename" fi if [ ! -f "$GLOBAL_index_filename" ] then exec > "$GLOBAL_index_filename" add_cleanup "$GLOBAL_index_filename" GLOBAL_stdout_has_been_redirected=1 else GLOBAL_stdout_has_been_redirected=0 fi make_file_readable "$GLOBAL_index_filename" fi } iterate_over_image_list () { local col first_row fn col=0 first_row=1 GLOBAL_last_row_was_closed=0 progress_update_start_creating_reduced_images while read fn do if [ $col -eq 0 ] then print_html_row_start GLOBAL_last_row_was_closed=0 fi print_html_column_start print_image_entry "$fn" print_html_column_end col=`expr $col + 1` if [ $col -eq $GLOBAL_columns ] then print_html_row_end col=0 GLOBAL_last_row_was_closed=1 fi done < $GLOBAL_image_list_tmpfile progress_update_done_creating_reduced_images } print_image_entry () { local fn thumb_width thumb_height was_reduced fn="$*" create_thumbnail "$fn" thumb_width=$RETURN_thumb_width thumb_height=$RETURN_thumb_height create_reduced "$fn" was_reduced=$RETURN_was_reduced print_image_link $thumb_width $thumb_height $was_reduced "$fn" print_image_size "$fn" } # Only reduce JPG images. Reducing GIF/PNG images is a little tricky - # see the RCS comment on rev 1.60 for more details on why this is tricky. maybe_remove_original () { local name reduced_name name="$*" RETURN_original_removed=0 RETURN_reduced_still_around=1 [ "$GLOBAL_remove_originals" -eq 0 ] && return if echo "$name" | grep -v '\.jpg$' > /dev/null 2>&1 then return fi source_name_to_reduced_name "$name" reduced_name="$RETURN_reduced_name" if [ -f "$name" -a -f "$reduced_name" -a -s "$reduced_name" ] then mv "$name" "${name}.bak" mv "$reduced_name" "$name" if [ ! -f "$reduced_name" -a -f "$name" -a -s "$name" ] then rm -f "${name}.bak" RETURN_original_removed=1 RETURN_reduced_still_around=0 else echo ERROR: I got confused while trying to remove original file >&2 echo ERROR: \"$name\"! Aborting... >&2 exit 1 fi fi } # A little complicated - parameters are # THUMBNAIL-WIDTH THUMBNAIL-HEIGHT REDUCED-IMG-MADE? FILENAME # $thumb_width $thumb_height $was_reduced "$fn" print_image_link () { local twidth theight reduced fn caption thumb_name local slideshow_name reduced_slideshow_name local image_name reduced_name main_link_href secondary_link_href twidth=$1; shift theight=$1; shift reduced=$1; shift fn="$*" get_image_caption "$fn" caption="$RETURN_caption" source_name_to_thumb_name "$fn" thumb_name="$RETURN_thumb_name" if [ $GLOBAL_create_slideshow -eq 1 ] then image_name_to_html_name "$fn" slideshow_name="$RETURN_html_name" source_name_to_reduced_html_name "$fn" reduced_slideshow_name="$RETURN_reduced_html_name" fi image_name="$fn" source_name_to_reduced_name "$image_name" reduced_name="$RETURN_reduced_name" # The logic ahead is complicated. We change our behavior depending # on whether (a) this image has a reduced version ($reduced), whether # (b) we are making slideshows ($GLOBAL_create_slideshow). # One odd case is if we are making a slideshow, and we are making reduced # versions of images, but _this_ particular image didn't have a reduced # version. In this one case, the _main_ link we emit is to the reduced # HTML slideshow page. That way when people do Next/Previous, they'll # proceed to the Reduced version (the one they most likely want). if [ $reduced -eq 1 ] then if [ $GLOBAL_create_slideshow -eq 1 ] then main_link_href="$reduced_slideshow_name" secondary_link_href="$slideshow_name" else main_link_href="$reduced_name" secondary_link_href="$image_name" fi else if [ $GLOBAL_create_slideshow -eq 1 ] then if [ $GLOBAL_reduce_big_pics -eq 1 ] then main_link_href="$reduced_slideshow_name" else main_link_href="$slideshow_name" fi else main_link_href="$image_name" fi fi echo -n ' " if [ $GLOBAL_print_captions -eq 1 ] then echo -n "
$caption
" if [ $reduced -eq 1 ] then echo -n "
[Large version]" fi else echo "" fi } print_image_size () { local bytes kbytes fn fn="$*" bytes=`ls -l "$fn" | awk '{print $5}'` kbytes=`expr $bytes / 1000` if [ $GLOBAL_print_captions -eq 1 ] then echo " (${kbytes}k)" fi } foo_to_pnm () { case "$*" in *.jpg) RETURN_foo_to_pnm="djpeg -ppm";; *.gif) RETURN_foo_to_pnm="giftopnm";; *.tif) RETURN_foo_to_pnm="tifftopnm";; *.png) RETURN_foo_to_pnm="pngtopnm";; *) echo ERROR: Unable to proceed with file "$*"! >&2 exit 1;; esac } source_name_to_thumb_name () { RETURN_thumb_name=`echo "$*" | sed 's,\.[^.]*$,-t.jpg,'` if [ "$*" = "$RETURN_thumb_name" ] then echo ERROR: I couldn\'t create a thumb name for "\"$*\""! >&2 exit 1 fi if echo "$RETURN_thumb_name" | egrep -- '-t-t\.' >/dev/null 2>&1 then echo ERROR: I couldn\'t create a reduced name for "\"$*\""! >&2 exit 1 fi } source_name_to_reduced_name () { RETURN_reduced_name=`echo "$*" | sed 's,\.[^.]*$,-r.jpg,'` if [ "$*" = "$RETURN_reduced_name" ] then echo ERROR: I couldn\'t create a reduced name for "\"$*\""! >&2 exit 1 fi if echo "$RETURN_reduced_name" | egrep -- '-r-r\.' >/dev/null 2>&1 then echo ERROR: I couldn\'t create a reduced name for "\"$*\""! >&2 exit 1 fi } source_name_to_source_html_name () { RETURN_source_html_name=`echo "$*" | sed 's,\.[^.]*$,.html,'` if [ "$*" = "$RETURN_source_html_name" ] then echo ERROR: I couldn\'t create an HTML name for "\"$*\""! >&2 exit 1 fi } image_name_to_html_name () { RETURN_html_name=`echo "$*" | sed 's,\.[^.]*$,.html,'` if [ "$*" = "$RETURN_html_name" ] then echo ERROR: I couldn\'t create an HTML name for "\"$*\""! >&2 exit 1 fi } html_name_to_image_name () { local fn basename imgname fn="$*" basename=`echo "$fn" | sed -e 's,-[rtl].html$,,' -e 's,.html$,,'` imgname=`grep "^${basename}.[jpgpnggif]*\$" $GLOBAL_image_list_tmpfile | head -1` RETURN_image_name="$imgname" if [ ! -f "$RETURN_image_name" ] then echo ERROR: I couldn\'t guess the image name for HTML file "\"$*\""! >&2 exit 1 fi } # We may have a reduced image, or we may not. If the reduced image # is present, we return the source image HTML name (so # source_name_to_source_html_name is equivalent to this function), # otherwise we return the reduced image HTML name. source_name_to_reduced_html_name () { local reduced_name source_name_to_reduced_name "$*" reduced_name="$RETURN_reduced_name" RETURN_reduced_html_name=`echo "$reduced_name" | sed 's,\.[jpgpnggif]*$,.html,'` if [ "$reduced_name" = "$RETURN_reduced_html_name" ] then echo ERROR: I couldn\'t create an HTML name for "\"$reduced_name\""! >&2 exit 1 fi } reduced_name_to_source_name () { local is_reduced_file nameroot source is_reduced_name "$*" if [ $RETURN_is_reduced_name -eq 1 ] then is_reduced_file=1 nameroot=`echo "$*" | sed 's,-r\.jpg$,,'` else is_reduced_file=0 nameroot=`echo "$*" | sed 's,\.[jpgpnggif]*$,,'` fi source=`grep "^${nameroot}\.[a-z][a-z][a-z]\$" $GLOBAL_image_list_tmpfile` if [ -z "$source" -o ! -f "$source" ] then echo ERROR: I couldn\'t find the source name from \"$*\"! >&2 exit 1 fi if [ "$*" = "$source" -a $is_reduced_file -eq 1 ] then echo ERROR: I couldn\'t find convert source name with \"$*\"! >&2 exit 1 fi RETURN_source_name="$source" } create_thumbnail () { local source_fn thumb_fn conv source_fn="$*" source_name_to_thumb_name "$source_fn" thumb_fn="$RETURN_thumb_name" if [ -f "$thumb_fn" -a -s "$thumb_fn" ] then # The existing thumbnail may be of the wrong size get_dimensions "$thumb_fn" if [ $RETURN_width -ne $GLOBAL_max_thumb_size -a \ $RETURN_height -ne $GLOBAL_max_thumb_size ] then rm -f "$thumb_fn" else RETURN_thumb_width=$RETURN_width RETURN_thumb_height=$RETURN_height make_file_readable "$thumb_fn" return fi fi foo_to_pnm "$source_fn" conv="$RETURN_foo_to_pnm" add_cleanup "$thumb_fn" check_for_rotation "$source_fn" $conv "$source_fn" | pnmscale -xysize $GLOBAL_max_thumb_size \ $GLOBAL_max_thumb_size 2>/dev/null | $RETURN_rotation_cmd $RETURN_rotation_angle | cjpeg -optimize -quality $GLOBAL_compression_level > "$thumb_fn" make_file_readable "$thumb_fn" remove_cleanup "$thumb_fn" progress_update_created_thumbnail_image if [ ! -s "$thumb_fn" ] then echo "ERROR: Unable to create thumbnail for \"$source_fn\"! Exiting." >&2 exit 1 fi get_dimensions "$thumb_fn" RETURN_thumb_width=$RETURN_width RETURN_thumb_height=$RETURN_height } create_reduced () { local source_fn reduced_fn start_conv source_fn="$*" source_name_to_reduced_name "$source_fn" reduced_fn="$RETURN_reduced_name" RETURN_was_reduced=0 if [ $GLOBAL_reduce_big_pics -eq 0 ] then return fi if [ -f "$reduced_fn" -a -s "$reduced_fn" ] then make_file_readable "$reduced_fn" maybe_remove_original "$source_fn" [ $RETURN_reduced_still_around -eq 1 ] && RETURN_was_reduced=1 return fi get_dimensions "$source_fn" if [ $RETURN_width -ge $GLOBAL_reduce_trigger_width -o \ $RETURN_height -ge $GLOBAL_reduce_trigger_height ] then foo_to_pnm "$source_fn" start_conv="$RETURN_foo_to_pnm" add_cleanup "$reduced_fn" check_for_rotation "$source_fn" $start_conv "$source_fn" | pnmscale -xysize $GLOBAL_reduce_width \ $GLOBAL_reduce_height 2>/dev/null | $RETURN_rotation_cmd $RETURN_rotation_angle | cjpeg -optimize -quality $GLOBAL_compression_level > "$reduced_fn" if [ $GLOBAL_jhead_is_present -eq 1 ] then jhead -te "$source_fn" "$reduced_fn" >/dev/null 2>&1 jhead -dt "$reduced_fn" >/dev/null 2>&1 fi make_file_readable "$reduced_fn" remove_cleanup "$reduced_fn" tag_image_with_text "$reduced_fn" progress_update_created_reduced_image maybe_remove_original "$source_fn" [ $RETURN_reduced_still_around -eq 1 ] && RETURN_was_reduced=1 fi if [ $RETURN_was_reduced -eq 1 -a ! -s "$reduced_fn" ] then echo "ERROR: Unable to create reduced img of \"$source_fn\"! Exiting." >&2 exit 1 fi } get_dimensions () { local fn conv dimens fn="$*" foo_to_pnm "$fn" conv="$RETURN_foo_to_pnm" dimens=`$conv "$fn" | pnmfile | awk '{print $4 " " $6}'` RETURN_width=`echo $dimens | cut -d ' ' -f1` RETURN_height=`echo $dimens | cut -d ' ' -f2` if [ -z "$RETURN_width" -o -z "$RETURN_height" ] then echo ERROR: Internal error in get_dimensions, for some reason I couldn\'t get >&2 echo ERROR: the dimensions of \"$fn\". Exiting. >&2 exit 1 fi } check_for_rotation () { local fn rot_cmd fn="$*" RETURN_do_rotation=0 RETURN_rotation_cmd=cat RETURN_rotation_angle="" [ ! -f $GLOBAL_rotation_filename ] && return if grep -i "^[a-z-]* ${fn}" $GLOBAL_rotation_filename >/dev/null 2>&1 then : else return fi rot_cmd=`grep -i "^[a-z-]* ${fn}" $GLOBAL_rotation_filename | sed "s/ ${fn}//"` if [ -z "$rot_cmd" ] then echo WARNING: Unrecognized rotation for "$fn"! Ignoring rotate. >&2 return fi if [ "$rot_cmd" != "clockwise" -a "$rot_cmd" != "counter-clockwise" ] then echo WARNING: Unrecognized rotation for "$fn"! Ignoring rotate. >&2 return fi RETURN_do_rotation=1 RETURN_rotation_cmd=pnmrotate if [ "$rot_cmd" = "clockwise" ] then RETURN_rotation_angle=-90 else RETURN_rotation_angle=90 fi } get_image_number () { local fn num total reduced_name_to_source_name "$*" fn="$RETURN_source_name" num=`cat -n $GLOBAL_image_list_tmpfile | grep "^[ ]*[0-9]*[ ]*${fn}\$" | cut -f1 | sed 's,[^0-9],,g'` if [ -z "$num" ] then echo WARNING: Could not get image number for file \"$fn\"! 1>&2 fi RETURN_image_number="$num" total=`cat $GLOBAL_image_list_tmpfile | wc -l | sed 's,[^0-9],,g'` if [ -z "$total" ] then echo WARNING: Could not determine number of image files! 1>&2 fi RETURN_number_of_images="$total" } tag_image_with_text () { local fn font_size font xoffset yoffset text fn="$*" [ -n "$GLOBAL_image_subtitle_text" ] || return [ "$GLOBAL_image_subtitle_text" = "undef" ] && return [ $GLOBAL_mogrify_is_present -eq 0 ] && return font_size=12 font="-*-helvetica-bold-r-*-*-${font_size}-*-*-*-*-*-iso8859-*" compute_subtitle_pixelwidth "$font_size" get_dimensions "$fn" xoffset=`expr $RETURN_width - $GLOBAL_image_subtitle_pixelwidth` [ $xoffset -le 0 ] && xoffset=0 yoffset=`expr $RETURN_height - $font_size` add_cleanup "$fn" text=`echo "$GLOBAL_image_subtitle_text" | sed "s,\",',g"` mogrify -fill yellow -font "$font" \ -draw "text ${xoffset},${yoffset} \"$text\"" "$fn" remove_cleanup "$fn" } # This function tries to determine the pixel width of a text string given # the string and given the font size that it'll be rendered in. I wish we # could just get the number directly from the imaging program that does it, # but I don't think I can. I need this information so I can justify the # text right-flush at the bottom of the image. # # The font is proportional, so these are just estimations. In short, # # upper-case char pixel width = font-size / 1.45 (8.27 pixels/char @ 12pts) # lower-case char pixel width = font-size / 2.20 (5.45 pixels/char @ 12pts) # space char pixel width = font-size / 2.22 (5.45 pixels/char @ 12pts) # all other chars pixel width = font-size / 1.60 (7.50 pixels/char @ 12pts) compute_subtitle_pixelwidth () { local font_size len len_padded lowcase upcase space otherchars pixellen font_size="$*" [ -n "$GLOBAL_image_subtitle_pixelwidth" ] && return len=`echo "$GLOBAL_image_subtitle_text" | wc -c | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` len_padded=`expr $len \* $font_size \* 10` lowcase=`echo "$GLOBAL_image_subtitle_text" | tr -cd '[a-z]' | wc -c | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` upcase=`echo "$GLOBAL_image_subtitle_text" | tr -cd '[A-Z0-9]' | wc -c | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` space=`echo "$GLOBAL_image_subtitle_text" | tr -cd '[ ]' | wc -c | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` otherchars=`expr $len - $upcase - $lowcase - $space` pixellen=`expr $lowcase \* $font_size \* 100 / 220` pixellen=`expr $pixellen + $upcase \* $font_size \* 100 / 145` pixellen=`expr $pixellen + $space \* $font_size \* 100 / 220` pixellen=`expr $pixellen + $otherchars \* $font_size \* 100 / 160` pixellen=`expr $pixellen + 2` GLOBAL_image_subtitle_pixelwidth="$pixellen" } ######################################################### #### HTML printing functions ######################################################### print_html_header () { get_directory_title echo '' echo '' echo '' echo " $RETURN_directory_title_inline" [ -n "$GLOBAL_meta_tag" -a "$GLOBAL_meta_tag" != undef ] && echo " $GLOBAL_meta_tag" if [ "$GLOBAL_html_charset" != "undef" ] then echo " " fi echo " " echo '' echo "$GLOBAL_body_tag" echo "" echo "

$RETURN_directory_title

" echo "" get_directory_description if [ -n "$RETURN_directory_description" ] then echo "

$RETURN_directory_description" echo "

" echo "" fi } print_html_table_start () { if [ $GLOBAL_compact_index_page -eq 1 ] then echo '' else echo '
' fi } print_html_table_end () { if [ $GLOBAL_last_row_was_closed -eq 0 ] then echo "" fi echo "" echo '
' } print_html_row_start () { echo "" echo '' } print_html_row_end () { echo '' echo "" if [ $GLOBAL_compact_index_page -eq 0 ] then # echo " " fi } print_html_column_start () { echo ' ' } print_html_column_end () { echo ' ' } # FIXME: I can't decide if the user's footer text should come # before the "This page created" text or after that text. If they're # putting a


tag, it would probably look better to put the # This Page text after the user's footer text. print_html_footer () { echo "" echo "

This page created on `date '+%Y-%m-%d'`." if [ -n "$GLOBAL_footer_text" -a "$GLOBAL_footer_text" != undef ] then echo "" echo "$GLOBAL_footer_text" echo "" fi cat << __EOM__ __EOM__ echo '' echo '' add_checksum_to_file "$GLOBAL_index_filename" if [ $GLOBAL_stdout_has_been_redirected -eq 1 ] then remove_cleanup "$GLOBAL_index_filename" fi } ######################################################### #### slideshow functions ######################################################### create_slideshow () { local fileset prev cur next [ $GLOBAL_create_slideshow -eq 0 ] && return progress_update_start_creating_slideshow_pages remove_existing_slideshow_html_files create_slideshow_image_list while read fileset do prev=`echo "$fileset" | cut -d\| -f1` cur=`echo "$fileset" | cut -d\| -f2` next=`echo "$fileset" | cut -d\| -f3` create_slideshow_source_file "$prev" "$cur" "$next" if [ $GLOBAL_reduce_big_pics -eq 1 -a $GLOBAL_remove_originals -ne 1 ] then create_slideshow_reduced_file "$prev" "$cur" "$next" fi progress_update_created_slideshow_page done < $GLOBAL_slideshow_image_list progress_update_done_creating_slideshow_pages } create_slideshow_source_file () { local prev_image cur_image next_image html_file prev_image="$1" cur_image="$2" next_image="$3" image_name_to_html_name "$cur_image" html_file="$RETURN_html_name" add_cleanup "$html_file" print_slideshow_file_header "$cur_image" "$html_file" print_slideshow_top_navlinks "$prev_image" "$cur_image" "$next_image" \ "source" "$html_file" print_slideshow_image "$cur_image" "$html_file" "source" print_slideshow_bottom_navlinks "$prev_image" "$cur_image" "$next_image" \ "source" "$html_file" print_image_exif_info "$cur_image" "$html_file" print_slideshow_file_footer "$html_file" remove_cleanup "$html_file" } create_slideshow_reduced_file () { local prev_image cur_image next_image local cur_source_image cur_reduced_image html_file prev_image="$1" cur_image="$2" next_image="$3" cur_source_image="$cur_image" cur_reduced_image="$cur_image" if [ "$prev_image" != NULL ] then source_name_to_reduced_name "$prev_image" prev_image="$RETURN_reduced_name" fi source_name_to_reduced_name "$cur_image" cur_reduced_image="$RETURN_reduced_name" if [ -f "$RETURN_reduced_name" ] then cur_image="$RETURN_reduced_name" fi if [ "$next_image" != NULL ] then source_name_to_reduced_name "$next_image" next_image="$RETURN_reduced_name" fi image_name_to_html_name "$cur_reduced_image" html_file="$RETURN_html_name" add_cleanup "$html_file" print_slideshow_file_header "$cur_image" "$html_file" print_slideshow_top_navlinks "$prev_image" "$cur_image" "$next_image" \ "reduced" "$html_file" print_slideshow_image "$cur_image" "$html_file" "reduced" print_slideshow_bottom_navlinks "$prev_image" "$cur_image" "$next_image" \ "reduced" "$html_file" print_image_exif_info "$cur_image" "$html_file" print_slideshow_file_footer "$html_file" remove_cleanup "$html_file" } print_slideshow_file_header () { local image_file html_file image_file="$1" html_file="$2" get_image_caption "$image_file" # The following exec goop so I don't have to manually redirect every # message to stderr in this function. exec 4>&1 # save stdout fd to fd #4 exec > "$html_file" # redirect stdout to stderr echo '' echo '' echo '' echo " $RETURN_caption_inline" [ -n "$GLOBAL_meta_tag" -a "$GLOBAL_meta_tag" != undef ] && echo " $GLOBAL_meta_tag" if [ "$GLOBAL_html_charset" != "undef" ] then echo " " fi echo " " echo ' ' echo '' echo "$GLOBAL_body_tag" echo "" get_directory_title if [ -n "$RETURN_directory_title_inline" ] then if [ $RETURN_directory_title_is_from_user -eq 1 ] then echo "

$RETURN_directory_title_inline / $RETURN_caption_inline

" elif [ -n "$RETURN_caption_was_from" -a \ $RETURN_caption_was_from = "descriptions-file" ] then echo "

$RETURN_caption_inline

" fi fi exec 1>&4 # Copy stdout fd back from temporary save fd, #4 make_file_readable "$html_file" } print_slideshow_file_footer () { local html_file html_file="$*" html_name_to_image_name "$html_file" get_image_description "$RETURN_image_name" if [ -n "$RETURN_image_description" ] then echo "

$RETURN_image_description
" >> "$html_file" fi if [ -n "$GLOBAL_footer_text" -a "$GLOBAL_footer_text" != undef ] then echo "" >> "$html_file" echo "$GLOBAL_footer_text" >> "$html_file" echo "" >> "$html_file" fi echo "" >> "$html_file" echo "" >> "$html_file" } print_slideshow_image () { local cur_image html_file type target_pre target_post cur_image="$1" html_file="$2" type="$3" target_pre="" target_post="" if [ "$type" = source ] then source_name_to_reduced_name "$cur_image" if [ -f "$RETURN_reduced_name" ] then image_name_to_html_name "$RETURN_reduced_name" target_pre="" target_post="" fi else is_reduced_name "$cur_image" if [ "$RETURN_is_reduced_name" -eq 1 ] then reduced_name_to_source_name "$cur_image" if [ -f "$RETURN_source_name" ] then image_name_to_html_name "$RETURN_source_name" target_pre="" target_post="" fi fi fi get_dimensions "$cur_image" echo "" >> "$html_file" echo "
$target_pre$target_post
" >> "$html_file" echo "" >> "$html_file" } # I think we'll try not emitting navlinks at the bottom for a while. print_slideshow_bottom_navlinks () { # print_slideshow_top_navlinks "$1" "$2" "$3" "$4" "$5" : } print_slideshow_top_navlinks () { local prev_image cur_image next_image page_type html_page local prev_html cur_html next_html local prev_markup middle_markup next_markup local imgno imgtotal right_text left_text prev_image="$1" cur_image="$2" next_image="$3" page_type="$4" html_page="$5" prev_html="$prev_image" cur_html="$cur_image" next_html="$next_image" middle_markup="" if [ "$prev_image" != NULL ] then image_name_to_html_name "$prev_image" prev_html="$RETURN_html_name" fi image_name_to_html_name "$cur_image" cur_html="$RETURN_html_name" if [ "$next_image" != NULL ] then image_name_to_html_name "$next_image" next_html="$RETURN_html_name" fi ## Emit link to previous image if [ "$prev_image" = NULL ] then prev_markup="$GLOBAL_slideshow_previous_pre_link$GLOBAL_slideshow_previous$GLOBAL_slideshow_previous_post_link" else prev_markup="$GLOBAL_slideshow_previous_pre_link$GLOBAL_slideshow_previous$GLOBAL_slideshow_previous_post_link" fi ## Emit link to next image if [ "$next_image" = NULL ] then next_markup="$GLOBAL_slideshow_next_pre_link$GLOBAL_slideshow_next$GLOBAL_slideshow_next_post_link" else next_markup="$GLOBAL_slideshow_next_pre_link$GLOBAL_slideshow_next$GLOBAL_slideshow_next_post_link" fi ## Emit link to index middle_markup="$GLOBAL_slideshow_ret_to_index_pre_link$GLOBAL_slideshow_ret_to_index$GLOBAL_slideshow_ret_to_index_post_link" ## Get "Image xx of yy" info get_image_number "$cur_image" imgno="$RETURN_image_number" imgtotal="$RETURN_number_of_images" if [ -n "$imgno" -a -n "$imgtotal" ] then right_txt="Image $imgno of $imgtotal" left_txt="" else right_txt=" " left_txt=" " fi ## Get image timestamp if we can guess it somehow get_image_time_date "$cur_image" if [ -n "$RETURN_time_date" ] then left_txt="$RETURN_time_date" fi echo '' >> "$html_page" echo '' >> "$html_page" echo "" >> "$html_page" echo " " >> "$html_page" echo ' ' >> "$html_page" echo " " >> "$html_page" echo '' >> "$html_page" echo '
$left_txt' >> "$html_page" echo ' ' >> "$html_page" echo " " >> "$html_page" echo " " >> "$html_page" echo " " >> "$html_page" echo " " >> "$html_page" echo " " >> "$html_page" echo '
$prev_markup $middle_markup $next_markup
' >> "$html_page" echo '
$right_txt
' >> "$html_page" echo '' >> "$html_page" } is_reduced_name () { RETURN_is_reduced_name=0 if echo "$*" | grep -- '-r\.[a-z][a-z][a-z]' >/dev/null 2>&1 then RETURN_is_reduced_name=1 fi } create_slideshow_image_list () { local number_of_files local prev_num cur_num next_num local prev_image cur_image next_image number_of_files=`cat $GLOBAL_image_list_tmpfile | wc -l | sed 's, ,,g'` cur_num=1 make_tmpfile ss-source GLOBAL_slideshow_image_list=$RETURN_tmpfile add_cleanup $GLOBAL_slideshow_image_list while [ $cur_num -le $number_of_files ] do prev_num=`expr $cur_num - 1` next_num=`expr $cur_num + 1` if [ $cur_num -eq 1 ] then prev_image=NULL else prev_image=`cat $GLOBAL_image_list_tmpfile | sed -n "${prev_num}p"` fi cur_image=`cat $GLOBAL_image_list_tmpfile | sed -n "${cur_num}p"` if [ $cur_num -eq $number_of_files ] then next_image=NULL else next_image=`cat $GLOBAL_image_list_tmpfile | sed -n "${next_num}p"` fi echo "${prev_image}|${cur_image}|${next_image}" >> $GLOBAL_slideshow_image_list cur_num=`expr $cur_num + 1` done } remove_existing_slideshow_html_files () { local file_list fn make_tmpfile file_list file_list=$RETURN_tmpfile add_cleanup $file_list ls -1 | grep '\.html' > $file_list while read fn do if grep "makethumbs generated HTML file which can be removed without warning" "$fn" >/dev/null 2>&1 then rm -f "$fn" fi done < $file_list } ######################################################### #### progress printing functions ######################################################### # This is the only updater fn where we _don't_ check that stdout has # been redirected, because it has yet to be redirected when this is called. progress_update_created_descriptions () { [ $GLOBAL_show_progress -eq 0 ] && return echo "Created $GLOBAL_descriptions_filename" >&2 } progress_update_start_creating_index_html () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo "Start creating $GLOBAL_index_filename" >&2 } progress_update_done_creating_index_html () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo "Done creating $GLOBAL_index_filename" >&2 } progress_update_start_creating_reduced_images () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo -n " Making reduced/thumbnail images " >&2 GLOBAL_did_we_reduce_anything=0 } progress_update_created_reduced_image () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo -n "o" >&2 GLOBAL_did_we_reduce_anything=1 } progress_update_created_thumbnail_image () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo -n "." >&2 GLOBAL_did_we_reduce_anything=1 } progress_update_done_creating_reduced_images () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return if [ $GLOBAL_did_we_reduce_anything -eq 0 ] then echo "(none regenerated)" >&2 else echo " done." >&2 fi } progress_update_start_creating_slideshow_pages () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo -n "Making slideshow pages " >&2 } progress_update_created_slideshow_page () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo -n "." >&2 } progress_update_done_creating_slideshow_pages () { [ $GLOBAL_stdout_has_been_redirected -eq 0 ] && return [ $GLOBAL_show_progress -eq 0 ] && return echo " done." >&2 } ######################################################### #### checksum checking functions, unmodified file removal ######################################################### remove_file_if_unmodified () { local filename filename="$*" verify_file_checksum "$filename" if [ $RETURN_cksum_ok -eq 1 ] then rm -f "$filename" return fi } # $RETURN_cksum_ok is '1' if a valid checksum is found. If no checksum # is found, or the checksum doesn't match, a '0' is returned (i.e. the # user may have modified this file for all we know). verify_file_checksum () { local filename sum_program recorded_sum sum_output filename="$*" RETURN_cksum_ok=0 if grep ',\1,'` recorded_sum=`grep ',\2,'` find_in_path "$sum_program" [ $RETURN_found -eq 0 ] && return sum_output=`grep -v '" >> "$filename" } normalize_checksum_string () { local istr istr="$*" istr=`echo "$istr" | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,' \ -e 's,[ ][ ]*, ,'` RETURN_str_norm="$istr" } ######################################################### #### descriptions.txt support ######################################################### create_descriptions_file () { local max i l [ -f $GLOBAL_descriptions_filename ] && return add_cleanup $GLOBAL_descriptions_filename echo '[short title] (best to avoid HTML markup here, keep it short,
s are OK)' > $GLOBAL_descriptions_filename echo '' >> $GLOBAL_descriptions_filename echo '' >> $GLOBAL_descriptions_filename echo '[longer page description] (all the HTML you want, as many lines as you want)' >> $GLOBAL_descriptions_filename echo '' >> $GLOBAL_descriptions_filename echo '' >> $GLOBAL_descriptions_filename echo '[captions] (best to avoid HTML markup here, keep it short,
s are OK)' >> $GLOBAL_descriptions_filename echo '' >> $GLOBAL_descriptions_filename # find max length of image names max=0 while read i do l=`echo "$i" | awk '{print length}'` [ $l -gt $max ] && max=$l done < $GLOBAL_image_list_tmpfile while read i do echo "$i" | awk "{printf (\"%-${max}s \\n\""', $0);}' >> $GLOBAL_descriptions_filename done < $GLOBAL_image_list_tmpfile echo '' >> $GLOBAL_descriptions_filename echo '[descriptions] (all the HTML you want, but each file on just one line)' >> $GLOBAL_descriptions_filename echo '' >> $GLOBAL_descriptions_filename while read i do echo "$i" | awk "{printf (\"%-${max}s \\n\""', $0);}' >> $GLOBAL_descriptions_filename done < $GLOBAL_image_list_tmpfile remove_cleanup $GLOBAL_descriptions_filename make_file_readable $GLOBAL_descriptions_filename progress_update_created_descriptions } # validate_descriptions_file () { local is_valid [ ! -f $GLOBAL_descriptions_filename ] && return [ $GLOBAL_descriptions_filename_validated -eq 1 ] && return [ $GLOBAL_descriptions_filename_is_invalid -eq 1 ] && return is_valid=`cat $GLOBAL_descriptions_filename | egrep '^\[short title\]|^\[longer page description\]|^\[captions\]|^\[descriptions\]' | awk 'BEGIN { state = 0 } { \ if ($1 == "[short" && $2 == "title]" && state == 0 ) { state = 1 ; next } if ($1 == "[longer" && $2 == "page" && state == 1) { state = 2 ; next} if ($1 == "[captions]" && state == 2) { state = 3; next} if ($1 == "[descriptions]" && state == 3) { print "ok"; next} print "error" }'` if [ -n "$is_valid" ] then if [ "$is_valid" = "ok" ] then GLOBAL_descriptions_filename_validated=1 else echo WARNING: Invalid $GLOBAL_descriptions_filename ! Ignoring. 1>&2 GLOBAL_descriptions_filename_is_invalid=1 fi fi } get_short_page_title_from_descriptions_file () { RETURN_short_page_title="" [ ! -f $GLOBAL_descriptions_filename ] && return validate_descriptions_file [ $GLOBAL_descriptions_filename_validated -eq 0 ] && return RETURN_short_page_title=`cat $GLOBAL_descriptions_filename | grep -v '^#' | awk 'BEGIN { seen_title = 0; seen_longerdesc = 0; } \ { \ if ($1 == "[short" && $2 == "title]") { seen_title = 1; next; } if (seen_title != 1) { next; } if ($1 == "[longer" && $2 == "page") { seen_longerdesc = 1; next; } if (seen_longerdesc == 1) { next; } print; }' | grep -v '^[ ]*$'` RETURN_short_page_title=`echo "$RETURN_short_page_title" | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` } get_page_description_from_descriptions_file () { RETURN_page_description="" [ ! -f $GLOBAL_descriptions_filename ] && return validate_descriptions_file [ $GLOBAL_descriptions_filename_validated -eq 0 ] && return RETURN_page_description=`cat $GLOBAL_descriptions_filename | grep -v '^#' | awk 'BEGIN { seen_longerdesc = 0; seen_captions = 0; } \ { \ if ($1 == "[longer" && $2 == "page") { seen_longdesc = 1; next; } if (seen_longdesc != 1) { next; } if ($1 == "[captions]") { seen_captions = 1; next; } if (seen_captions == 1) { next; } print; }' | grep -v '^[ ]*$'` RETURN_page_description=`echo "$RETURN_page_description" | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` } get_image_caption_from_descriptions_file () { local fn fn="$*" RETURN_image_caption="" [ ! -f $GLOBAL_descriptions_filename ] && return [ -z "$fn" ] && return validate_descriptions_file [ $GLOBAL_descriptions_filename_validated -eq 0 ] && return reduced_name_to_source_name "$fn" fn="$RETURN_source_name" RETURN_image_caption=`\ egrep "^${fn}"' |^\[captions\]|^\[descriptions\]' \ $GLOBAL_descriptions_filename | awk 'BEGIN { seen_captions = 0; seen_desc = 0; } \ { \ if ($1 == "[captions]") { seen_captions = 1; next; } if (seen_captions != 1) { next; } if ($1 == "[descriptions]") { seen_desc = 1; next; } if (seen_desc == 1) { next; } print }' | grep -v '^[ ]*$' | head -1` RETURN_image_caption=`echo "$RETURN_image_caption" | sed "s/${fn}//" | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` } get_image_description_from_descriptions_file () { local fn fn="$*" RETURN_image_description="" [ ! -f $GLOBAL_descriptions_filename ] && return [ -z "$fn" ] && return validate_descriptions_file [ $GLOBAL_descriptions_filename_validated -eq 0 ] && return reduced_name_to_source_name "$fn" fn="$RETURN_source_name" RETURN_image_description=`\ egrep "^${fn}"' |^\[captions\]|^\[descriptions\]' \ $GLOBAL_descriptions_filename | awk 'BEGIN { seen_desc = 0; } \ { \ if ($1 == "[descriptions]") { seen_desc = 1; next; } if (seen_desc != 1) { next; } print }' | grep -v '^[ ]*$' | head -1` RETURN_image_description=`echo "$RETURN_image_description" | sed "s/${fn}//" | sed -e 's,^[ ]*,,' -e 's,[ ]*$,,'` } ## The functions that the rest of the script will use: get_image_caption () { local fn fn="$*" get_image_caption_from_descriptions_file "$fn" if [ -n "$RETURN_image_caption" ] then RETURN_caption="$RETURN_image_caption" RETURN_caption_was_from="descriptions-file" RETURN_caption_inline=`echo "$RETURN_caption" | sed -e 's, *<[Bb][Rr]> *, ,g' -e 's, *<[Bb][Rr] */> *, ,g'` else RETURN_caption=`echo "$fn" | sed -e 's,-[tr]\.[a-z][a-z][a-z]$,,' \ -e 's,\.[a-z][a-z][a-z]$,,' \ -e 's,-, ,g' -e 's,_, ,g'` RETURN_caption_inline="$RETURN_caption" RETURN_caption_was_from="filename" fi } get_image_description () { get_image_description_from_descriptions_file "$*" } get_directory_title () { local t get_short_page_title_from_descriptions_file if [ -n "$RETURN_short_page_title" ] then RETURN_directory_title="$RETURN_short_page_title" RETURN_directory_title_inline=`echo "$RETURN_short_page_title" | sed -e 's, *<[Bb][Rr]> *, ,g' -e 's, *<[Bb][Rr] */> *, ,g'` RETURN_directory_title_is_from_user=1 else t=`pwd` RETURN_directory_title=`basename "$t"` RETURN_directory_title_inline="$RETURN_directory_title" RETURN_directory_title_is_from_user=0 fi } get_directory_description () { get_page_description_from_descriptions_file RETURN_directory_description="$RETURN_page_description" } ######################################################### #### Get EXIF et al information and add it to slideshow pages ######################################################### # This function should add the photo information using a variety # of programs to recover the EXIF data embedded in the JPEG. Alas, # I haven't found any decent programs to get this in a good format # on Unix systems, so for now I take the easy approach of supporting # the INFO.TXT file that my Nikon Coolpix 995 creates. # A little more work is needed for configuration. Should this be disableable? # Should it have an option to print the shot info in the slideshow HTML # visibly, instead of an HTML comment? I bet some people would prefer # that. For now, this will only benefit me, so I'll leave it as is until # I find a way to get the general EXIF information out of a JPG file. print_image_exif_info () { local fn html fn="$1" html="$2" reduced_name_to_source_name "$fn" fn="$RETURN_source_name" print_coolpix_info_txt "$fn" "$html" } print_coolpix_info_txt () { local fn html fn="$1" html="$2" get_coolpix_info_txt "$fn" if [ -n "$RETURN_info_txt" ] then echo "" >> "$html" echo "" >> "$html" fi } get_coolpix_info_txt () { local filename lineno filename="$*" RETURN_info_txt="" [ ! -f INFO.TXT ] && return reduced_name_to_source_name "$filename" filename="$RETURN_source_name" if cat INFO.TXT | tr -d '\r' | grep -i "^$filename\$" >/dev/null 2>&1 then : else return fi lineno=`cat -n INFO.TXT | tr -d '\r' | grep -i "^[ ]*[0-9]*[ ]*$filename\$" | cut -f1 | sed 's,[^0-9],,g'` RETURN_info_txt=`cat INFO.TXT | tr -d '\r' | sed "1,${lineno}d" | awk '{if (NF == 0) { exit } print " " $0;}' | grep -v '^[ ]*$'` } ######################################################### #### Try to get image time/date data via a variety of means ######################################################### get_image_time_date () { local fn reduced_name_to_source_name "$*" fn="$RETURN_source_name" RETURN_time_date="" get_time_date_via_metacam "$fn" if [ -n "$RETURN_metacam_time_date" ] then RETURN_time_date="$RETURN_metacam_time_date" return fi get_time_date_via_exiftools "$fn" if [ -n "$RETURN_exiftools_time_date" ] then RETURN_time_date="$RETURN_exiftools_time_date" return fi get_coolpix_time_date "$fn" if [ -n "$RETURN_coolpix_time_date" ] then RETURN_time_date="$RETURN_coolpix_time_date" return fi get_chillcam_time_date "$fn" if [ -n "$RETURN_chillcam_time_date" ] then RETURN_time_date="$RETURN_chillcam_time_date" return fi get_time_date_via_strings "$fn" if [ -n "$RETURN_strings_time_date" ] then RETURN_time_date="$RETURN_strings_time_date" return fi guess_date_via_directory_name if [ -n "$RETURN_guessed_date" ] then RETURN_time_date="$RETURN_guessed_date" return fi get_olympus_date "$fn" if [ -n "$RETURN_olympus_date" ] then RETURN_time_date="$RETURN_olympus_date" return fi try_ians_filename_format "$fn" if [ -n "$RETURN_ians_date" ] then RETURN_time_date="$RETURN_ians_date" return fi try_erics_filename_format "$fn" if [ -n "$RETURN_erics_date" ] then RETURN_time_date="$RETURN_erics_date" return fi } # Get one of these lines from metacam output : # # Image Creation Date: 2001:12:23 13:39:48 # Image Capture Date: 2001:12:23 13:39:48 # Image Digitized Date: 2001:12:23 13:39:48 # # All three may be present, or only one may be present. get_time_date_via_metacam () { local fn td [ $GLOBAL_metacam_is_present -eq 0 ] && return fn="$*" RETURN_metacam_time_date="" td=`metacam "$fn" 2>/dev/null | egrep -i 'Image (Creation|Capture|Digitized) Date' | grep -v '0000:00:00 00:00' | head -1 | awk '{print $(NF-1) " " $NF}' | sed -e 's,[^0-9: ],,g' \ -e 's,\([12][0-9][0-9][0-9]\):\([01][0-9]\):\([0-3][0-9]\) \([012][0-9]\):\([0-6][0-9]\).*,\1-\2-\3 \4:\5,'` if [ -n "$td" ] then RETURN_metacam_time_date="$td" fi } # Get this line from dump-exif (a part of exif-tools) output : # # DateTimeOriginal: 2000:04:19 15:01:56 get_time_date_via_exiftools () { local fn td [ $GLOBAL_dumpexif_is_present -eq 0 ] && return fn="$*" RETURN_exiftools_time_date="" td=`dump-exif "$fn" 2>/dev/null | egrep -i 'DateTimeOriginal' | grep -v '0000:00:00 00:00' | head -1 | awk '{print $(NF-1) " " $NF}' | sed -e 's,[^0-9: ],,g' \ -e 's,\([12][0-9][0-9][0-9]\):\([01][0-9]\):\([0-3][0-9]\) \([012][0-9]\):\([0-6][0-9]\).*,\1-\2-\3 \4:\5,'` if [ -n "$td" ] then RETURN_exiftools_time_date="$td" fi } get_coolpix_time_date () { local fn timestamp fn="$*" RETURN_coolpix_time_date="" get_coolpix_info_txt "$fn" if [ -n "$RETURN_info_txt" ] then timestamp=`echo "$RETURN_info_txt" | grep '^[ ]*DATE' | awk '{print $3 " " $4}' | sed 's,\.,-,g' | sed 's,[^0-9 :-],,g'` if [ -n "$timestamp" ] then RETURN_coolpix_time_date="$timestamp" return fi fi } # See if we can find the date string with good old strings(1). # The date is in there in the form of 2001:11:19 19:25:09 get_time_date_via_strings () { local fn="$*" local td RETURN_strings_time_date="" td=`strings "$fn" 2>/dev/null | grep -v '0000:00:00 00:00' | egrep '(19|20)[0-9][0-9]:(0[1-9]|1[0-2]):[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]' | head -1 | awk '{print $(NF-1) " " $NF}' | sed -e 's,[^0-9: ],,g' \ -e 's,\([12][0-9][0-9][0-9]\):\([01][0-9]\):\([0-3][0-9]\) \([012][0-9]\):\([0-6][0-9]\).*,\1-\2-\3 \4:\5,'` if [ -n "$td" ] then RETURN_strings_time_date="$td" fi } # Olympus cameras (C2000Z, C2020Z, C3030Z) have photo filenames in the form of # P<4-DIGIT-SEQ-NO>.jpg # If a person hasn't set the time/date in the camera, MONTH-DIGIT (a hex # dgit) and DAY are 1, giving you a name of the form P101xxxx.jpg, which # should be ignored. Yes, this means that photos taken on New Year's Day # will not be recognized. get_olympus_date () { local fn="$*" local month day RETURN_olympus_date="" if echo "$fn" | egrep '^P[1-9A-Ca-c][0-3][0-9][0-9][0-9][0-9][0-9].jpg$' >/dev/null 2>&1 then month=`echo "$fn" | sed -e 's,^P\(.\).*,\1,' \ -e 's,^1$,January,' -e 's,^2$,February,' -e 's,^3$,March,' \ -e 's,^4$,April,' -e 's,^5$,May,' -e 's,^6$,June,' \ -e 's,^7$,July,' -e 's,^8$,August,' -e 's,^9$,September,' \ -e 's,^[aA]$,October,' -e 's,^[bB]$,November,' \ -e 's,^[cC]$,December,'` day=`echo "$fn" | sed -e 's,^P.\([0-3][0-9]\).*,\1,' -e 's,^0,,'` if [ -n "$month" -a -n "$day" ] then [ "$month" = January -a "$day" = "1" ] && return RETURN_olympus_date="$month $day" fi fi } # This only tries to recognize dates in some form of YYYY-MM-DD. # Americans might expect MM-DD-YYYY to work, or MM-DD-YY, but # it's not globally unambiguous, so those Americans may now learn # the joys of ISO 8601. Unless I feel like adding support for # the US formats some day. Don't hold your breath. guess_date_via_directory_name () { local t exp canonical_fmt local fmt1 fmt2 fmt3 fmt4 fmt5 fmt6 fmt7 fmt8 [ $GLOBAL_already_failed_guessing_date_from_dir -eq 1 ] && return t=`pwd` t=`basename "$t"` RETURN_guessed_date="" # Don't re-do work we've aready done during this makethumbs run. if [ -n "$GLOBAL_static_var_guessed_date_from_dirname" ] then RETURN_guessed_date="$GLOBAL_static_var_guessed_date_from_dirname" return fi canonical_fmt="[12][09][0-9][0-9]-[012][0-9]-[0-3][0-9]" fmt1="$canonical_fmt" fmt2="[12][09][0-9][0-9]-[012]?[0-9]-[0-3]?[0-9]" fmt3="[12][09][0-9][0-9]_[012][0-9]_[0-3][0-9]" fmt4="[12][09][0-9][0-9]_[012]?[0-9]_[0-3]?[0-9]" fmt5="[12][09][0-9][0-9]\.[012][0-9]\.[0-3][0-9]" fmt6="[12][09][0-9][0-9]\.[012]?[0-9]\.[0-3]?[0-9]" fmt7="[12][09][0-9][0-9] [012]?[0-9] [0-3]?[0-9]" fmt8="[12][09][0-9][0-9][012][0-9][0-3][0-9]" for exp in "$fmt1" "$fmt2" "$fmt3" "$fmt4" "$fmt5" "$fmt6" "$fmt7" "$fmt8" do if echo "$t" | egrep "$exp" >/dev/null 2>&1 then t=`echo "$t" | sed "s/.*\(${exp}\).*/\1/" | awk '{\ datepat="^.*\([12][09][0-9][0-9]\)[^0-9]*\([01]?[0-9]\)[^0-9]*\([0-3]?[0-9]\)[^0-9]?.*$" year = gensub (datepat, "\\\\1", "g", $0); month = gensub (datepat, "\\\\2", "g", $0); day = gensub (datepat, "\\\\3", "g", $0); printf ("%s-%02d-%02d", year, month, day); }'` if echo "$t" | egrep "$canonical_fmt" >/dev/null 2>&1 then RETURN_guessed_date="$t" GLOBAL_static_var_guessed_date_from_dirname="$t" return fi fi done GLOBAL_already_failed_guessing_date_from_dir=1 } # ChillCAM is a web cam program that embeds the time/date in the comment field. # www.chillcam.com # format is "MM/DD/YYYY HH:MM:SS" get_chillcam_time_date () { local fn t fn="$*" t="" RETURN_chillcam_time_date="" if [ $GLOBAL_rdjpgcom_is_present -eq 0 -a \ $GLOBAL_jhead_is_present -eq 0 -a \ $GLOBAL_jpegtopnm_is_present -eq 0 ] then return fi if [ $GLOBAL_rdjpgcom_is_present -eq 1 ] then t=`rdjpgcom "$fn" 2>/dev/null | grep -i chillcam | head -1` fi if [ -z "$t" -a $GLOBAL_jhead_is_present -eq 1 ] then t=`jhead "$fn" 2>/dev/null | grep -i chillcam | head -1` fi if [ -z "$t" -a $GLOBAL_jpegtopnm_is_present -eq 1 ] then t=`jpegtopnm -comment "$fn" 2>&1 >/dev/null | grep -i chillcam | head -1` fi [ -z "$t" ] && return t=`echo "$t" | awk '{print $(NF-1) " " $NF}' | sed -e 's,[^0-9/: ],,g' | grep '[01][0-9]/[0-3][0-9]/[12][0-9][0-9][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]' | sed -e 's,\([01][0-9]\)/\([0-3][0-9]\)/\([12][0-9][0-9][0-9]\) \([012][0-9]\):\([0-6][0-9]\).*,\3-\1-\2 \4:\5,'` [ -z "$t" ] && return RETURN_chillcam_time_date="$t" } #### USA SPECIFIC DATE FORMAT CHECKS ## Dates can be ordered by month/day/year or they can be ordered by ## day/month/year, depending on which part of the world you live in. ## I'd rather everyone use an ISO8601 unambiguous date, but they don't. ## The following timestamp checks all assume a US (MM/DD/year) format ## date string, and they can all be disabled by setting ## usa_specific_date_format_checks to zero in your .makethumbsrc file. # Ian Lance Taylor has his images named # MMDDYY-n+.jpg. # (where 'n' is the sequence number on that day). # I cheat and assume that years "00" - "29" are 2000-2029 and years # "70-99" are 1970-1999. try_ians_filename_format () { local fn t fn="$*" RETURN_ians_date="" [ $GLOBAL_usa_specific_date_format_checks -eq 0 ] && return if echo "$fn" | egrep '^(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-27-9][0-9]-[1-9][0-9]*\.[jpgpnggif]{3}$' >/dev/null 2>&1 then t=`echo "$fn" | sed -e 's|^\([01][0-9]\)\([0-3][0-9]\)\([0-2][0-9]\).*|20\3-\1-\2|' \ -e 's|^\([01][0-9]\)\([0-3][0-9]\)\([7-9][0-9]\).*|19\3-\1-\2|'` if [ -n "$t" ] then if echo "$t" | egrep '^(19|20)[0-9][0-9]-[01][0-9]-[0-3][0-9]$' >/dev/null 2>&1 then RETURN_ians_date="$t" return fi fi fi } # Eric Perlman names his files with the date encoded in the filename # in a format like "foo_(3-2-2002).jpg". (i.e. *MM-DD-YYYY* s.t. MM and DD # can be single digit.) try_erics_filename_format () { local fn t month day year fn="$*" RETURN_erics_date="" [ $GLOBAL_usa_specific_date_format_checks -eq 0 ] && return if echo "$fn" | egrep '[(](0?[1-9]|1[0-2])-(0?[1-9]|[12][0-9]|3[01])-(19|20)[0-9][0-9][)]' >/dev/null 2>&1 then year=`echo "$fn" | sed -e 's|.*[(]\([0-9]*\)-\([0-9]*\)-\([12][09][0-9][0-9]\)[)].*|\3|'` month=`echo "$fn" | sed -e 's|.*[(]\([0-9]*\)-\([0-9]*\)-\([12][09][0-9][0-9]\)[)].*|\1|'` day=`echo "$fn" | sed -e 's|.*[(]\([0-9]*\)-\([0-9]*\)-\([12][09][0-9][0-9]\)[)].*|\2|'` t=`printf "%s-%02d-%02d" "$year" "$month" "$day" 2>/dev/null` if [ -n "$t" ] then if echo "$t" | egrep '^(19|20)[0-9][0-9]-[01][0-9]-[0-3][0-9]$' >/dev/null 2>&1 then RETURN_erics_date="$t" return fi fi fi } ######################################################### #### call to main ######################################################### main $*