#! /bin/sh # This script creates tumbnails, reduced versions of large images, and an # index.html file pointing to all of it. # 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 # (4) portable portable portable # There are many programs that violate 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. ## Guidelines for hacking: ## ## Start at main() and trace the function calls from there. ## Remember that there is no scoping of variables, so local variables aren't. ## You'll see some function-local variables with common names ("$fn" etc) ## prefixed with an abbreviation of the function name so that they don't ## overwrite a similarly named variable in the caller. ## No cycles in the call graph or you'll lose. ## As much as I like Bourne shell, I probably 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. ## Return variables are prefixed with "RETURN_". Command line options ## are prefixed with "ARGV_". Defaults are prefixed with "DEFAULT_", ## and globals are prefixed with "GLOBAL_". ## GLOBAL_ will hold all the settings that we should act on. These came ## either from a DEFAULT_ or an ARGV_ if the user overrode the DEFAULT_. ## This script used to have no functions at all, but I found that annoying ## to maintain, so now I've embraced function-mania. main () { init_defaults read_dotrc_file find_needed make_dir_transversible "." parse_args $* get_image_list point_stdout_to_index_file [ $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 [ $GLOBAL_create_slideshow -eq 1 ] && create_slideshow exit 0 } create_slideshow () { [ $GLOBAL_create_slideshow -eq 0 ] && return 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 done < $GLOBAL_slideshow_image_list } create_slideshow_source_file () { cssf_prev_image="$1" cssf_cur_image="$2" cssf_next_image="$3" image_name_to_html_name "$cssf_cur_image" cssf_html_file="$RETURN_html_name" add_cleanup "$cssf_html_file" print_slideshow_file_header "$cssf_cur_image" "$cssf_html_file" print_slideshow_top_navlinks "$cssf_prev_image" "$cssf_cur_image" \ "$cssf_next_image" "source" "$cssf_html_file" print_slideshow_image "$cssf_cur_image" "$cssf_html_file" "source" print_slideshow_bottom_navlinks "$cssf_prev_image" "$cssf_cur_image" \ "$cssf_next_image" "source" "$cssf_html_file" print_slideshow_file_footer "$cssf_html_file" remove_cleanup "$cssf_html_file" } create_slideshow_reduced_file () { cssf_prev_image="$1" cssf_cur_image="$2" cssf_next_image="$3" cssf_cur_source_image="$cssf_cur_image" cssf_cur_reduced_image="$cssf_cur_image" if [ "$cssf_prev_image" != NULL ] then source_name_to_reduced_name "$cssf_prev_image" cssf_prev_image="$RETURN_reduced_name" fi source_name_to_reduced_name "$cssf_cur_image" cssf_cur_reduced_image="$RETURN_reduced_name" if [ -f "$RETURN_reduced_name" ] then cssf_cur_image="$RETURN_reduced_name" fi if [ "$cssf_next_image" != NULL ] then source_name_to_reduced_name "$cssf_next_image" cssf_next_image="$RETURN_reduced_name" fi image_name_to_html_name "$cssf_cur_reduced_image" cssf_html_file="$RETURN_html_name" add_cleanup "$cssf_html_file" print_slideshow_file_header "$cssf_cur_image" "$cssf_html_file" print_slideshow_top_navlinks "$cssf_prev_image" "$cssf_cur_image" \ "$cssf_next_image" "reduced" "$cssf_html_file" print_slideshow_image "$cssf_cur_image" "$cssf_html_file" "reduced" print_slideshow_bottom_navlinks "$cssf_prev_image" "$cssf_cur_image" \ "$cssf_next_image" "reduced" "$cssf_html_file" print_slideshow_file_footer "$cssf_html_file" remove_cleanup "$cssf_html_file" } print_slideshow_file_header () { psfh_image_file="$1" psfh_html_file="$2" get_file_english_name "$psfh_image_file" psfh_english_name="$RETURN_english_name" # 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 > "$psfh_html_file" # redirect stdout to stderr echo '' echo '' echo '' echo " $psfh_english_name" [ -n "$GLOBAL_meta_tag" ] && echo "$GLOBAL_meta_tag" if [ "$GLOBAL_html_charset" != "undef" ] then echo " " fi echo ' ' echo '' echo "$GLOBAL_body_tag" echo '' echo "" exec 1>&4 # Copy stdout fd back from temporary save fd, #4 make_file_readable "$psfh_html_file" } print_slideshow_file_footer () { psff_html_file="$1" echo '' >> "$psff_html_file" echo "" >> "$psff_html_file" echo "" >> "$psff_html_file" } print_slideshow_image () { psi_cur_image="$1" psi_html_file="$2" psi_type="$3" psi_target_pre="" psi_target_post="" if [ $psi_type = source ] then source_name_to_reduced_name "$psi_cur_image" if [ -f "$RETURN_reduced_name" ] then image_name_to_html_name "$RETURN_reduced_name" psi_target_pre="" psi_target_post="" fi else is_reduced_name "$psi_cur_image" if [ "$RETURN_is_reduced_name" -eq 1 ] then reduced_name_to_source_name "$psi_cur_image" if [ -f "$RETURN_source_name" ] then image_name_to_html_name "$RETURN_source_name" psi_target_pre="" psi_target_post="" fi fi fi get_dimensions "$psi_cur_image" echo "" >> "$psi_html_file" echo "

" >> "$psi_html_file" echo "

$psi_target_pre$psi_target_post
" >> "$psi_html_file" echo "

" >> "$psi_html_file" echo "" >> "$psi_html_file" } print_slideshow_bottom_navlinks () { print_slideshow_top_navlinks "$1" "$2" "$3" "$4" "$5" } print_slideshow_top_navlinks () { pstn_prev_image="$1" pstn_cur_image="$2" pstn_next_image="$3" pstn_page_type="$4" pstn_html_page="$5" pstn_prev_html="$pstn_prev_image" pstn_cur_html="$pstn_cur_image" pstn_next_html="$pstn_next_image" pstn_middle_markup="" if [ "$pstn_prev_image" != NULL ] then image_name_to_html_name "$pstn_prev_image" pstn_prev_html="$RETURN_html_name" fi image_name_to_html_name "$pstn_cur_image" pstn_cur_html="$RETURN_html_name" if [ "$pstn_next_image" != NULL ] then image_name_to_html_name "$pstn_next_image" pstn_next_html="$RETURN_html_name" fi ## Emit link to previous image if [ "$pstn_prev_image" = NULL ] then pstn_prev_markup="$GLOBAL_slideshow_previous_pre_link$GLOBAL_slideshow_previous$GLOBAL_slideshow_previous_post_link" else pstn_prev_markup="$GLOBAL_slideshow_previous_pre_link$GLOBAL_slideshow_previous$GLOBAL_slideshow_previous_post_link" fi ## Emit link to next image if [ "$pstn_next_image" = NULL ] then pstn_next_markup="$GLOBAL_slideshow_next_pre_link$GLOBAL_slideshow_next$GLOBAL_slideshow_next_post_link" else pstn_next_markup="$GLOBAL_slideshow_next_pre_link$GLOBAL_slideshow_next$GLOBAL_slideshow_next_post_link" fi ## Emit link to index pstn_middle_markup="$GLOBAL_slideshow_ret_to_index_pre_link$GLOBAL_slideshow_ret_to_index$GLOBAL_slideshow_ret_to_index_post_link" echo '' >> "$pstn_html_page" echo '' >> "$pstn_html_page" echo '

' >> "$pstn_html_page" echo " " >> "$pstn_html_page" echo " " >> "$pstn_html_page" echo " " >> "$pstn_html_page" echo '
$pstn_prev_markup$pstn_middle_markup$pstn_next_markup
' >> "$pstn_html_page" echo '' >> "$pstn_html_page" echo '' >> "$pstn_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 () { 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 () { 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 } # RETURN_found is 1 if found, 0 if not found. If found, $RETURN_fullname # contains the path + filename. find_in_path () { target="$1" RETURN_found=0 OFS="$IFS" IFS=: for i in $PATH do if [ -z "$i" ] then dir="." else dir="$i" fi if [ -f "$dir/$target" ] then RETURN_fullname="$dir/$target" RETURN_found=1 break fi done IFS="$OFS" } # 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 () { dotrc_file="$HOME/.makethumbsrc" GLOBAL_found_dotrc_vars=0 [ ! -f "$dotrc_file" ] && return make_tmpfile dotrc tmpf=$RETURN_tmpfile add_cleanup $tmpf cat "$dotrc_file" | grep -v '^[ ]*#' | grep = > $tmpf [ ! -s $tmpf ] && return 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_,,'` value=`echo "$line" | sed -e 's,^[^=]*=,,' -e 's,^[ ]*,,' \ -e 's,[ ]*$,,' \ -e s,^\[\"\'\]\[\ \ \]\*,, \ -e s,\[\ \ \]\*\[\"\'\]\$,, \ -e 's,",\\\\",g'` # Some of what the above sed does: Remove spaces at beginning or end. # Remove " or ' marks at end/begin, and any spaces after them. # Backslash escape any " marks so the evals below work right. eval [ -n \"\$GLOBAL_$varname\" ] && varname_is_valid=1 if [ $varname_is_valid -eq 0 ] then echo ERROR: "$dotrc_file" 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 numberic 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 GLOBAL_found_dotrc_vars=1 eval DOTRC_$varname=\"$value\" eval GLOBAL_$varname=\$DOTRC_$varname done < $tmpf } # Returns a temp file in $RETURN_tmpfile. # Takes an optional description name argument. make_tmpfile () { find_in_path mktemp if [ $RETURN_found -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_needed () { 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 } update_cleanups () { trap "rm -f $GLOBAL_cleanuplist; exit 1" 0 1 2 15 } add_cleanup () { GLOBAL_cleanuplist="$GLOBAL_cleanuplist $*" update_cleanups } remove_cleanup () { for i in $* do GLOBAL_cleanuplist=`echo $GLOBAL_cleanuplist | sed "s,${i},,"` done 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 } # 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_max_thumb_width=$DEFAULT_max_thumb_size DEFAULT_max_thumb_height=$DEFAULT_max_thumb_size DEFAULT_use_two_windows=0 DEFAULT_reduce_big_pics=1 DEFAULT_reduce_trigger_height=768 DEFAULT_reduce_trigger_width=1024 DEFAULT_reduce_height=600 DEFAULT_reduce_width=800 DEFAULT_remove_originals=0 DEFAULT_create_slideshow=1 t=`pwd` DEFAULT_pwd_english=`basename "$t"` DEFAULT_rotation_file="rot-state.txt" DEFAULT_body_tag="" DEFAULT_meta_tag="" DEFAULT_html_charset="undef" 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_width=$DEFAULT_max_thumb_width GLOBAL_max_thumb_height=$DEFAULT_max_thumb_height 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_pwd_english="$DEFAULT_pwd_english" GLOBAL_rotation_file=$DEFAULT_rotation_file 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_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 } parse_args () { 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_height=$ARGV_max_thumb_size GLOBAL_max_thumb_width=$ARGV_max_thumb_size ;; --maxthumbheight=* | --max-thumb-height=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_max_thumb_height=$optarg exit_if_empty GLOBAL_max_thumb_height=$ARGV_max_thumb_height ;; --maxthumbwidth=* | --max-thumb-width=*) optarg=`echo $optarg | sed 's,[^0-9],,g'` exit_if_empty "$optname" "$optarg" ARGV_max_thumb_width=$optarg GLOBAL_max_thumb_width=$ARGV_max_thumb_width ;; --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 ;; --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 ;; --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 ;; -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 } exit_if_empty () { desc="$1" shift val="$*" if [ -z "$val" ] then echo ERROR: No argument given with \"$desc\" command line argument! >&2 exit 1 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` [--maxthumbsize=n] [--columns=n] [--show-filesize] [--use-two-windows] [--disable-reduce] [filenames...] --maxthumbsize Maximum size of thumbnails, in pixels, default $DEFAULT_max_thumb_size --columns Number of thumbnails per line, default $DEFAULT_columns --disable-reduce Don't create a reduced img if the picture is large --disable-slideshow Don't create slideshow files --use-two-windows Bring up a new window to see images, default is `[ $DEFAULT_use_two_windows -eq 1 ] && echo enabled || echo disabled` --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 index.html. If an index.html is already present, its HTML is sent to stdout. 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. You need to use the program's internal variable names here. For instance, if you always want --use-two-windows mode, the internal name is $GLOBAL_use_two_windows so you'd need to set use_two_windows=1 in your .makethumbsrc. Most usefully, you can specify what kind of tag you want used in your web page with a setting like body_tag= Determining the variable names for the .makethumbsrc is not very user friendly, but I suspect this feature will not be widely used. If I'm wrong, I'll see about making it a little more user friendly. This script written by Jason Molenda, makethumbs(AT)molenda.com. This is version '$Revision: 1.67 $'. 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 } # Sets file at $GLOBAL_image_list_tmpfile with images to process. # Tries to normalize filename extensions. get_image_list () { 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\.' >/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 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 index.html ] then exec > index.html fi make_file_readable index.html fi } iterate_over_image_list () { col=0 first_row=1 while read fn do if [ $col -eq 0 ] then print_html_row_start 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 fi done < $GLOBAL_image_list_tmpfile } print_image_entry () { pie_fn="$*" create_thumbnail "$pie_fn" thumb_width=$RETURN_thumb_width thumb_height=$RETURN_thumb_height create_reduced "$pie_fn" was_reduced=$RETURN_was_reduced print_image_link $thumb_width $thumb_height $was_reduced "$pie_fn" print_image_size "$pie_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 () { mro_name="$1" RETURN_original_removed=0 RETURN_reduced_still_around=1 [ "$GLOBAL_remove_originals" -eq 0 ] && return if echo "$mro_name" | grep -v '\.jpg$' > /dev/null 2>&1 then return fi source_name_to_reduced_name "$mro_name" mro_reduced_name="$RETURN_reduced_name" if [ -f "$mro_name" -a -f "$mro_reduced_name" -a -s "$mro_reduced_name" ] then mv "$mro_name" "${mro_name}.bak" mv "$mro_reduced_name" "$mro_name" if [ ! -f "$mro_reduced_name" -a -f "$mro_name" -a -s "$mro_name" ] then rm -f "${mro_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: \"$mro_name\"! Aborting... >&2 exit 1 fi fi } get_file_english_name () { gfen_fn="$*" RETURN_english_name=`echo "$gfen_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'` } # A little complicated - parameters are # THUMBNAIL-WIDTH THUMBNAIL-HEIGHT REDUCED-IMG-MADE? FILENAME # $thumb_width $thumb_height $was_reduced "$fn" print_image_link () { twidth=$1; shift theight=$1; shift reduced=$1; shift pil_fn="$*" get_file_english_name "$pil_fn" pil_english_name="$RETURN_english_name" source_name_to_thumb_name "$pil_fn" pil_thumb_name="$RETURN_thumb_name" if [ $GLOBAL_create_slideshow -eq 1 ] then image_name_to_html_name "$pil_fn" pil_slideshow_name="$RETURN_html_name" source_name_to_reduced_html_name "$pil_fn" pil_reduced_slideshow_name="$RETURN_reduced_html_name" fi pil_image_name="$pil_fn" source_name_to_reduced_name "$pil_image_name" pil_reduced_name="$RETURN_reduced_name" if [ $reduced -eq 1 ] then if [ $GLOBAL_create_slideshow -eq 1 ] then main_link_href="$pil_reduced_slideshow_name" secondary_link_href="$pil_slideshow_name" else main_link_href="$pil_reduced_name" secondary_link_href="$pil_image_name" fi else if [ $GLOBAL_create_slideshow -eq 1 ] then main_link_href="$pil_slideshow_name" else main_link_href="$pil_image_name" fi fi echo -n ' " echo -n "
$pil_english_name
" if [ $reduced -eq 1 ] then echo -n "
[Large version]" fi } print_image_size () { bytes=`ls -l "$fn" | awk '{print $5}'` kbytes=`expr $bytes / 1000` echo " (${kbytes}k)" } 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 "$fn"! >&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 } # We may have a reduced image, or we may not. If the reduced image # is present, we return the source image HTML name (so # sourc_name_to_source_html_name is equivalent to this function), # otherwise we return the reduced image HTML name. source_name_to_reduced_html_name () { source_name_to_reduced_name "$*" sntrhn_reduced_name="$RETURN_reduced_name" if [ ! -f "$sntrhn_reduced_name" ] then source_name_to_source_html_name "$*" RETURN_reduced_html_name="$RETURN_source_html_name" else RETURN_reduced_html_name=`echo "$sntrhn_reduced_name" | sed 's,\.[^.]*$,.html,'` fi if [ "$sntrhn_reduced_name" = "$RETURN_reduced_html_name" ] then echo ERROR: I couldn\'t create an HTML name for "\"$sntrhn_reduced_name\""! >&2 exit 1 fi } reduced_name_to_source_name () { rntsn_nameroot=`echo "$*" | sed 's,-r\.jpg$,,'` rntsn_source=`grep "${rntsn_nameroot}\.[a-z][a-z][a-z]\$" $GLOBAL_image_list_tmpfile` if [ -z "$rntsn_source" -o ! -f "$rntsn_source" ] then echo ERROR: I couldn\'t find the source name from \"$*\"! >&2 exit 1 fi if [ "$*" = "$rntsn_source" ] then echo ERROR: I couldn\'t find convert source name with \"$*\"! >&2 exit 1 fi RETURN_source_name="$rntsn_source" } create_thumbnail () { source_fn="$*" source_name_to_thumb_name "$source_fn" thumb_fn="$RETURN_thumb_name" if [ -f "$thumb_fn" -a -s "$thumb_fn" ] then make_file_readable "$thumb_fn" get_dimensions "$thumb_fn" RETURN_thumb_width=$RETURN_width RETURN_thumb_height=$RETURN_height return 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_width \ $GLOBAL_max_thumb_height 2>/dev/null | $RETURN_rotation_cmd $RETURN_rotation_angle | cjpeg -optimize > "$thumb_fn" make_file_readable "$thumb_fn" remove_cleanup "$thumb_fn" 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 () { cr_source_fn="$*" source_name_to_reduced_name "$cr_source_fn" cr_reduced_fn="$RETURN_reduced_name" RETURN_was_reduced=0 if [ $GLOBAL_reduce_big_pics -eq 0 ] then return fi if [ -f "$cr_reduced_fn" -a -s "$cr_reduced_fn" ] then make_file_readable "$cr_reduced_fn" maybe_remove_original "$cr_source_fn" [ $RETURN_reduced_still_around -eq 1 ] && RETURN_was_reduced=1 return fi get_dimensions "$cr_source_fn" if [ $RETURN_width -ge $GLOBAL_reduce_trigger_width -o \ $RETURN_height -ge $GLOBAL_reduce_trigger_height ] then foo_to_pnm "$cr_source_fn" start_conv="$RETURN_foo_to_pnm" add_cleanup "$cr_reduced_fn" check_for_rotation "$cr_source_fn" $start_conv "$cr_source_fn" | pnmscale -xysize $GLOBAL_reduce_width \ $GLOBAL_reduce_height 2>/dev/null | $RETURN_rotation_cmd $RETURN_rotation_angle | cjpeg -optimize > "$cr_reduced_fn" make_file_readable "$cr_reduced_fn" remove_cleanup "$cr_reduced_fn" maybe_remove_original "$cr_source_fn" [ $RETURN_reduced_still_around -eq 1 ] && RETURN_was_reduced=1 fi if [ $RETURN_was_reduced -eq 1 -a ! -s "$cr_reduced_fn" ] then echo "ERROR: Unable to create reduced img of \"$source_fn\"! Exiting." >&2 exit 1 fi } get_dimensions () { gd_fn="$*" foo_to_pnm "$gd_fn" conv="$RETURN_foo_to_pnm" dimens=`$conv "$gd_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 \"$gd_fn\". Exiting. >&2 exit 1 fi } check_for_rotation () { cfr_fn="$*" RETURN_do_rotation=0 RETURN_rotation_cmd=cat RETURN_rotation_angle="" [ ! -f $GLOBAL_rotation_file ] && return if grep -i "^[a-z-]* ${fn}" $GLOBAL_rotation_file >/dev/null 2>&1 then : else return fi rot_cmd=`grep -i "^[a-z-]* ${fn}" $GLOBAL_rotation_file | sed "s, ${fn},,"` if [ -z "$rot_cmd" ] then echo WARNING: Unrecognized rotation for "$cfr_fn"! Ignoring rotate. >&2 return fi if [ "$rot_cmd" != "clockwise" -a "$rot_cmd" != "counter-clockwise" ] then echo WARNING: Unrecognized rotation for "$cfr_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 } print_html_header () { echo '' echo '' echo '' echo " $GLOBAL_pwd_english" [ -n "$GLOBAL_meta_tag" ] && echo "$GLOBAL_meta_tag" if [ "$GLOBAL_html_charset" != "undef" ] then echo " " fi echo '' echo "$GLOBAL_body_tag" echo "" echo "

$GLOBAL_pwd_english

" echo "" } print_html_table_start () { echo '' } print_html_table_end () { echo "" echo '
' } print_html_row_start () { echo "" echo '' } print_html_row_end () { echo '' echo "" # echo " " } print_html_column_start () { echo ' ' } print_html_column_end () { echo ' ' } print_html_footer () { echo "" echo "

This page created on `date '+%Y-%m-%d'`." cat << __EOM__ __EOM__ echo '' echo '' } main $*