#!/bin/bash # # This script scans the given JPEG files (whose names # must end in .jpg), generates a thumbnail and a reduced # version in JPEG of each, and generates an HTML page with all the # thumbnails and links to the reduced version and the original. # # If the image contains PhotoRDF (wrapped in Adobe's XMP), it is used # to generate a description. # # The HTML page with thumbnails is written to the first argument: # # thumbnails index.html *.jpg # # Options: see the function "help" below. # # This script relies on the PBM (or ImageMagick) and JPEG tools to be # installed. # # TO DO: handle file names with spaces. # # Author: Bert Bos # Created: 8 July 1999 # Version: $Date: 2013-03-14 15:25:20 $ # # Copyright (c) 1995-2010 World Wide Web Consortium, (Massachusetts # Institute of Technology, ERCIM, Keio University). All Rights # Reserved. See # http://www.w3.org/Consortium/Legal/copyright-software.html progname="${0##*/}" # die -- print error message and exit function die { echo "$progname: $*" >&2; exit 1; } # Other parameters w1=100 # Width of thumbnail smallwd=640 # Max. width of smaller version smallht=480 # Max. height of smaller version thdir=thumb # Name of thumbnail directory smdir=small # Name of smaller images directory pagetitle="Thumbnails" # Unless overridden by "-t" language="en" # Language of generated HTML pages owner="Bert Bos" # Copyright holder email="bert@w3.org" # Copyright holder's e-mail preamble= # Unless overridden by -p style= # Unless overridden by -e interactive=false # Whether to prompt for title, language, etc. group= # Group by series/year/nothing crop=100 # Percentage of image to show in thumbnail up=".." # Where the "up" link points to xmplink=static # Put the XMP data from each image in a file htaccess=false # Don't write a .htaccess file prevlink= # URL for nextlink= # URL for osm_zoom=-1 # Zoom for link to OpenStreetMap (-1 = no link) OSM='http://www.openstreetmap.org/' # Base URL for Web-based OSM map # Some constants for the interactive dialogs # d_backtitle="Thumbnails RDF/XMP" # Check that we have jpegtopnm/pnmtojpeg, convert, or djpeg/cjpeg. # (In fact, when convert exists, CJPEG and DJPEG aren't used at all.) # if type -t djpeg >/dev/null; then DJPEG="djpeg" elif type -t convert >/dev/null; then DJPEG="convert - ppm:-" elif type -t jpegtopnm >/dev/null; then DJPEG="jpegtopnm" else die "Neither djpeg, jpegtopnm nor convert found." fi if type -t cjpeg >/dev/null; then CJPEG=cjpeg elif type -t convert >/dev/null; then CJPEG="convert - -quality 75 jpeg:-" elif type -t pnmtojpeg >/dev/null; then CJPEG=pnmtojpeg else die "Neither cjpeg, pnmtojpeg nor convert found." fi # We need wrjpgapp, and either convert or pnmscale # if type -t wrjpgapp >/dev/null; then :; else die "Required program wrjpgapp not found." fi if type -t pnmscale >/dev/null || type -p convert >/dev/null; then :; else die "Neither convert nor pnmscale programs found." fi # We also need dc (for the latitude/longitude conversion). # if type -t dc >/dev/null; then :; else die "Required program dc not found." fi # Constants (RDF field names). Note: Between rdfpic 2.0 and 2.1, we # changed the names of the properties to lowercase, as is the # convention for RDF. # dc='http://purl.org/dc/elements/1.1/' tc='http://www.w3.org/2000/PhotoRDF/technical-1-0#' exif="http://ns.adobe.com/exif/1.0/" tiff='http://ns.adobe.com/tiff/1.0/' xap='http://ns.adobe.com/xap/1.0/' dcDescription="${dc}description" dcCoverage="${dc}coverage" dcDate="${dc}date" dcTitle="${dc}title" dcIdentifier="${dc}identifier" dcCreator="${dc}creator" dcContributor="${dc}contributor" dcRelation="${dc}relation" dcRights="${dc}rights" tcCamera="${tc}camera" tcLens="${tc}lens" tcFilm="${tc}film" tcDevelDate="${tc}devel-date" exifLatitude="${exif}GPSLatitude" exifLongitude="${exif}GPSLongitude" tiffModel="${tiff}Model" exifDateTimeOriginal="${exif}DateTimeOriginal" xapCreateDate="${xap}CreateDate" # Localization languages=(\ "en"\ "nl"\ "fr"\ "de") Legend=(\ "Legend"\ "Legenda"\ "Légende"\ "Legende") Large=(\ "large image"\ "grote foto"\ "grande photo"\ "große Foto") Small=(\ "small image (max ${smallwd}×${smallht})"\ "kleine foto (max ${smallwd}×${smallht})"\ "petite photo (${smallwd}×${smallht} max)"\ "kleine Foto") Raw=(\ "raw RDF/XMP metadata"\ "ruwe RDF/XMP metadata"\ "metadata RDF/XMP cru"\ "rohe RDF/XMP metadata") Previous=(\ "Previous"\ "Vorige"\ "Précédent"\ "Vorige") Index=(\ "Index"\ "Index"\ "Index"\ "Index") Next=(\ "Next"\ "Volgende"\ "Suivant"\ "Nächste") Image=(\ "[image]"\ "[foto]"\ "[photo]"\ "[Foto]") Date=(\ "Date:"\ "Datum:"\ "Date :"\ "Datum:") Place=(\ "Place:"\ "Plaats:"\ "Lieu :"\ "Ort:") Series=(\ "Series:"\ "Serie:"\ "Série :"\ "Serie:") Number=(\ "Number:"\ "Nummer:"\ "Numéro :"\ "Nummer:") Creator=(\ "Photographer:"\ "Fotograaf:"\ "Photographe :"\ "Fotograf:") Contributor=(\ "Contributor:"\ "Medewerker:"\ "Collaborateur:"\ "Mitarbeiter:") Rights=(\ "Rights:"\ "Rechten:"\ "Droits :"\ "Rechte:") Size=(\ "Size:"\ "Grootte:"\ "Taille :"\ "Größe:") Camera=(\ "Camera:"\ "Camera:"\ "Appareil photo :"\ "Kamera:") Lens=(\ "Lens:"\ "Lens:"\ "Objectif :"\ "Objektiv:") Film=(\ "Film:"\ "Film:"\ "Pellicule :"\ "Film:") DevelDate=(\ "Development date:"\ "Ontwikkeldatum:"\ "Date de developpement :"\ "Entwiklungsdatum:") Latitude=(\ "Latitude:"\ "Breedtegraad:"\ "Latitude :"\ "Geographische Breite:") Longitude=(\ "Longitude:"\ "Lengtegraad:"\ "Longitude :"\ "Geographische Länge:") # A directory for temporary files. The directory will be removed when # the script exits, so no need to remove temporary files after use. # TEMPDIR=`mktemp -d /tmp/thumb-XXXXXX` || exit 1 trap "rm -rf $TEMPDIR" 0 # usage -- print usage message and exit function usage { echo "Usage: $progname [-ihgxya] [-t title] [-l language] [-n owner] [-m e-mail] [-c percent] [-w width] [-p file] [-s style-link] [-U up-link] [-P prev-link] [-N next-link] [-z OSM-zoom] output jpeg [jpeg...]" exit 1 } # help -- explain the options function help { echo "$progname -- create thumbnails and description pages for JPEG images" echo "Options and arguments:" echo " -l language" echo " Output HTML in the given language. Currently supported" echo " are \"en\" (English), \"fr\" (French), \"nl\" (Dutch) and" echo " \"de\" (German). Default: en" echo " -t title" echo " Title of the generated thumbnails page. May contain" echo " inline mark-up. Default: \"Thumbnails\"" echo " -n name" echo " The name of the copyright owner, which will be printed at" echo " the bottom of the page. If the images do not contain RDF" echo " metadata, a copyright message will be inserted into them" echo " as well." echo " Default: \"Bert Bos\"" echo " -c percent" echo " Try to make thumbnails better by showing only the center" echo " of the image. 100 means the whole image is used" echo " (default), 80 means the image's four edges are cut off" echo " such that only 80% of its original width and height" echo " remain" echo " -p file" echo " Insert the contents of file above the thumbnails." echo " Must be HTML that is valid in BODY." echo " Default: none" echo " -w number" echo " Width or height (whichever is larger) of the thumbnails," echo " in pixels." echo " Default: 100" echo " -s style-link" echo " URI reference of an external style sheet. If present, all" echo " generated pages (thumbnail page and individual photo pages)" echo " will have a with this URI. Otherwise," echo " the script will insert its own built-in style." echo " -g" echo " Group the thumbnails by series (dc:relation), add a subtitle" echo " before each group and a menu of series at the top." echo " -y" echo " Group the thumbnails by year (dc:date), add a subtitle" echo " before each group and a menu of years at the top." echo " (-g and -y are mutually exclusive.)" echo " -x" echo " Don't make a separate file with the XMP data, but assume the" echo " server can extract the XMP on request. (The Jigsaw server can" echo " do this, e.g.)" echo " -a" echo " Create or update the .htaccess file (for an Apache server)" echo " with some lines so that .jpg and .xmp files are served with" echo " right media types." echo " -U URL" echo " URI reference of a document that will be the \"up\" link from" echo " the thumbnails page. The default is \"..\". This will insert" echo " in the thumbnails page." echo " -P URL" echo " URI reference of a document that will be the \"previous\"" echo " document for the thumbnails page. No default. If present, this" echo " adds a to the thumbnails page." echo " -N URL" echo " Analogous. If present, this adds a to" echo " the thumbnails page." echo " -z OSM-zoomlevel" echo " Add a link to OpenStreetMap with the given zoom level for" echo " every photo that has latitude/longitude information." echo " Default: -1 (= no link)." echo " -i" echo " Interactive. The user will be prompted for language," echo " title, name of owner, output file and image files." echo " -h" echo " Help. Shows this text." echo " output" echo " The name of the HTML file which will contain the" echo " thumbnails. Use \"-\" to print to standard output." echo " jpeg [jpeg...]" echo " All remaining arguments are interpreted as JPEG files to" echo " be processed. The program will create a small version" echo " (max. 640x480) in the directory \"small\", unless the" echo " original is already smaller than that. And it will create" echo " a thumbnail (max. 100x100) in the directory \"thumb\". It" echo " also creates one HTML file for each JPEG file with the" echo " small version of the image and the description. If there" echo " is no description in Photo-RDF format inside the JPEG," echo " the description will consist of just the file name." exit; } # rdjpgxmp -- extract XMP from a JPEG/JFIF file if ! type -p rdjpgxmp >/dev/null; then function rdjpgxmp { # tr is needed because of a bug in GNU sed 4.1: "." doesn't match null bytes sed '/]*W5M0MpCehiHzreSzNTczkc9d/,/]*>\).*/\1/' } fi # get_xmp -- get the XMP data, extract it if not yet extracted function get_xmp { local xmpfile=${1%.*}.xmp if [ $xmplink = dynamic ]; then rdjpgxmp "$1" elif [[ -f "$xmpfile" && "$xmpfile" -nt "$1" ]]; then cat "$xmpfile" else rdjpgxmp "$1" | tee "$xmpfile" fi } # extract -- get value of field $1 from embedded XMP $2, escape double quotes function extract { if type -p xmptool >/dev/null; then local h=`xmptool -l $language $1 $2` [[ -z "$h" ]] && h=`xmptool -l x-default $1 $2` # If not found, try default [[ -z "$h" ]] && h=`xmptool $1 $2` # If not found, try any language # echo "$h" | sed -e 's/"/\"/g' echo "${h//\"/"}" else local field=${1##*/} field=${field##*#} # LC_ALL=C is needed, because the sed command on Mac OS X 10.6.8 cannot handle UTF-8 tr '\n' ' ' <$2 |\ LC_ALL=C sed -n ' # Remove , as it may interfere with old s|]*>||g s|]*>||g # Remove Namespace prefixes s|<[a-zA-Z0-9_-]*:|<|g s|\).*|\1|g # Quit if there was no such property t cont q :cont # Remove everything before wanted language s|.*\(<[^>]*xml:lang=.'$language'\)|\1|g # Remove everything after first closing tag s|]*>||g # Collapse white space, escape double quotes s| *| |g s| $|| s|^ || s|"|\"|g p ' fi } # getsize -- get size of file $1 in KB function getsize { #set -- `ls -s -k "$1"` # We need the first word of the output #echo $1 set -- `wc -c "$1"` echo $(($1 / 1024)) } # scale -- scale a JPEG image on stdin to fit within $1 x $2 pixels function scale { # convert copies all JPEG comment chunks (EXIF, XMP, etc.), but # djpeg doesn't, so we add the contents of file $3 in the latter # case. # if type -t convert >/dev/null; then convert -size $1x$2 - -resize $1x$2 -quality 75 - else $DJPEG | pnmscale -xysize $1 $2 | $CJPEG | wrjpgapp -cfile $3 fi } # crop_and_scale -- scale the center $1 % of a JPEG image $4 to $2x$3 function crop_and_scale { if type -t convert >/dev/null; then local fileinfo=`identify -format '%wx%h' "$4"` local -i w=${fileinfo%x*} local -i h=${fileinfo#*x} local -i shavew=$((w * (100 - $1) / 200)) local -i shaveh=$((h * (100 - $1) / 200)) convert "$4" -shave ${shavew}x${shaveh} -resize $2x$3 -strip - else local fileinfo=`$DJPEG <"$4" | pnmfile` fileinfo=${fileinfo#*,} local -i w=${fileinfo%by*} fileinfo=${fileinfo#*by} local -i h=${fileinfo%maxval*} local -i l=$(((w - (w * crop / 100)) / 2)) local -i t=$(((h - (h * crop / 100)) / 2)) $DJPEG <"$4" |\ pnmcut -left $l -right -$l -top $t -bottom -$t |\ pnmscale -xysize $1 $2 | $CJPEG fi } # get_dimension -- return the size of a JPEG image on stdin function get_dimension { if type -p identify >/dev/null; then identify -format '%w %h' - else djpeg | pnmfile | cut -d, -f2 | cut -d' ' -f2,4 fi } # output_header -- Write the header part of the output function output_header { # Note: 'float: left' causes a bug in Netscape 4 and Opera 3.5 & 3.6 # (all images are in a single row, instead of as many as needed). # You may want to comment it out until there are newer versions of # those browsers. local heading="$1" local title=`echo "$heading" | sed -e 's/<[^>]*>//g'` local fontsize=$((w1/10)) local lineheight=$((w1/8)) local boxwd=$((w1 + w1/2)) echo "" echo "" echo "" echo "$title" if [ -z "$style" ]; then cat <<-EOF EOF else echo "" fi echo "" if [ ! -z "$prevlink" ]; then echo ""; fi if [ ! -z "$nextlink" ]; then echo ""; fi if [ ! -z "$email" ]; then echo -e "" fi echo echo "" echo "

$heading

" } # output_footer -- output copyright message, etc. at the end function output_footer { echo "
" echo "Copyright © "`date +%Y`" $owner" echo "
" echo "" echo "" } # ask_pagetitle -- put up a dialog with an input box for the page title function ask_pagetitle { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." $DIALOG --backtitle "$d_backtitle"\ --inputbox "Title for thumbnails page" 10 60 "$pagetitle" 2>$TMP case $? in 0) pagetitle="$(<$TMP)";; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac } # ask_owner_and_email -- put up a dialog for the copyright owner function ask_owner_and_email { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." $DIALOG --backtitle "$d_backtitle"\ --form "Copyright owner" 11 60 2\ "Name" 1 1 "$owner" 1 17 37 5000\ "E-mail" 2 1 "$email" 2 17 37 5000 2>$TMP case $? in 0) IFS=$'\n' read -d $'\0' owner email <$TMP;; # OK, read two lines 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac } # ask_images -- Ask for the names of all the JPEG images to process function ask_images { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." $DIALOG --backtitle "$d_backtitle"\ --inputbox "The JPEG images (e.g., \"*.jpg\")" 10 70 "$images" 2>$TMP case $? in 0) images="$(<$TMP)";; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac } # ask_output -- put up a dialog for the name of the generated thumbnails page function ask_output { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." local done=false until [ $done == true ]; do until $DIALOG --backtitle "$d_backtitle"\ --extra-button --extra-label "Browse"\ --inputbox "Output file name (\"-\" for standard out)"\ 10 60 "$output" 2>$TMP do case $? in 1|255) exit;; # Cancel|ESC 3) $DIALOG --backtitle "$d_backtitle"\ --fselect "${output:-./}" 9 60 2>$TMP case $? in 0) output="$(<$TMP)";; 1|255) ;; *) die "Bug! Cannot happen!";; esac;; *) die "Bug! Cannot happen!";; esac done output="$(<$TMP)" if [ -z "$output" ]; then $DIALOG --backtitle "$d_backtitle"\ --msgbox "The file name cannot be empty. If you want output\ to be printed to standard output, use a single dash (\"-\")"\ 12 60 else done=true fi done } # ask_language -- present the choice of output languages function ask_language { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." local en=off fr=off nl=off de=off case "$language" in en) en=on;; fr) fr=on;; nl) nl=on;; de) de=on;; esac $DIALOG --backtitle "$d_backtitle"\ --radiolist "Language for HTML pages" 12 40 5\ en "English" $en\ de "German [Deutsch]" $de\ fr "French [Français]" $fr\ nl "Dutch [Nederlands]" $nl 2>$TMP case $? in 0) language="$(<$TMP)";; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac } # ask_preamble -- ask for the name of a file to insert function ask_preamble { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." until $DIALOG --backtitle "$d_backtitle"\ --extra-button --extra-label "Browse"\ --inputbox "Optional file with text to insert" 10 60 "$preamble" 2>$TMP do case $? in 1|255) exit;; # Cancel|ESC 3) $DIALOG --backtitle "$d_backtitle"\ --fselect "${preamble:-./}" 9 60 2>$TMP case $? in 0) preamble="$(<$TMP)";; 1|255) ;; *) die "Bug! Cannot happen!";; esac;; *) die "Bug! Cannot happen!";; esac done preamble="$(<$TMP)" } # ask_percentage -- put up a dialog for the percentage crop of thumbnails function ask_percentage { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." local again=true while [ $again = true ]; do $DIALOG --backtitle "$d_backtitle"\ --max-input 3 --trim\ --inputbox "Percentage of photo shown in thumbnail (100 = everything)" 10 40 "$crop" 2>$TMP case $? in 0) crop="$(<$TMP)";; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac case "$crop" in [1-9] | [1-9][0-9] | 100) again=false;; *) $DIALOG --backtitle "$d_backtitle"\ --msgbox "The percentage must be between 1 and 100. Values smaller\ than 100 cause the thumbnail to show only the center part\ of the photo."\ 12 60 again=true;; esac done } # ask_thumbnail_size -- put up a dialog for the size of thumbnails function ask_thumbnail_size { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." local again=true while [ $again = true ]; do $DIALOG --backtitle "$d_backtitle"\ --max-input 3 --trim\ --inputbox "Size of thumbnails (in pixels)" 10 40 "$w1" 2>$TMP case $? in 0) w1="$(<$TMP)";; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac case "$w1" in [1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]) again=false;; *) $DIALOG --backtitle "$d_backtitle"\ --msgbox "The size must be between 1 and 9999."\ 12 60 again=true;; esac done } # ask_grouping -- ask if the thumbnails should be grouped function ask_grouping { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." local none=off series=off year=off case "$group" in series) series=on;; year) year=on;; *) none=on;; esac $DIALOG --backtitle "$d_backtitle"\ --radiolist "Group thumbnails?" 10 60 3\ "" "Don't group" $none\ "series" "By series" $series\ "year" "By year" $year 2>$TMP case $? in 0) group=$(<$TMP);; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac } # ask_xmplink -- ask if the XMP should be made available in a separate file function ask_xmplink { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." local static=off dynamic=off case $xmplink in static) static=on;; dynamic) dynamic=on;; *) die 'Cannot happen! Impossible value in function ask_xmplink';; esac $DIALOG --backtitle "$d_backtitle"\ --radiolist "Make each image's XMP data available in a file?" 9 64 2\ "static" "Yes, make an XMP file for each image" $static\ "dynamic" "No, let the server extract the XMP on demand" $dynamic 2>$TMP case $? in 0) xmplink=$(<$TMP);; # OK 1|255) exit;; # Cancel|ESC *) die 'Cannot happen! Impossible exit code in function ask_xmplink';; esac } # ask_style -- ask for the URL of an external style sheet function ask_style { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." $DIALOG --backtitle "$d_backtitle"\ --inputbox "Optional external style sheet" 10 60 "$style" 2>$TMP case $? in 0) style="$(<$TMP)";; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac } # ask_nav_links -- ask for the URL of "rel=up/prev/next" links function ask_nav_links { local TMP=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." #$DIALOG --backtitle "$d_backtitle"\ # --inputbox "Link for rel=up" 10 60 "$up" 2>$TMP $DIALOG --backtitle "$d_backtitle"\ --form "Navigation links" 10 60 3\ "" 1 1 "$up" 1 17 37 5000\ "" 2 1 "$prevlink" 2 17 37 5000\ "" 3 1 "$nextlink" 3 17 37 5000 2>$TMP case $? in 0) IFS=$'\n' read -d $'\0' up prevlink nextlink <$TMP;; # OK 1|255) exit;; # Cancel|ESC *) die "Bug! Cannot happen!";; esac } # minutes-to-dec -- convert latitude or longitude to decimal form function minutes-to-dec { local h d m s c h=${1%?}; c=${1#${h}} d=${h%%,*}; h=${h#${d}}; h=${h#,} m=${h%%,*}; h=${h#${m}}; h=${h#,} s=${h}; h=${h#${s}} if [ -z "$h" ]; then case "$c" in N|E) echo "4k${d:-0} ${m:-0} ${s:-0} 60/+60/+p" | dc;; S|W) echo "4k0 ${d:-0} ${m:-0} ${s:-0} 60/+60/+-p" | dc;; esac fi } # Parse options while getopts "hagyxit:l:n:m:c:w:p:s:N:P:U:z:" flag; do case $flag in "i") interactive=true;; "t") pagetitle="$OPTARG";; "l") language="$OPTARG";; "n") owner="$OPTARG";; "m") email="$OPTARG";; "c") crop="$OPTARG";; "w") w1="$OPTARG";; "p") preamble="$OPTARG";; "s") style="$OPTARG";; "g") group=series;; "y") group=year;; "x") xmplink=dynamic;; "a") htaccess=true;; "N") nextlink="$OPTARG";; "P") prevlink="$OPTARG";; "U") up="$OPTARG";; "z") osm_zoom="$OPTARG";; "h") help;; "?") usage;; esac done shift $((OPTIND - 1)) # Parse the name of the HTML file to output to $interactive || [[ "$1" != "" ]] || usage output="$1" shift images="$*" # Check for a common mistake: # if file "$output" | grep JPEG >/dev/null; then die "For safety, will not overwrite $output" fi # Check if the dialog program is present. # DIALOG=`type -p dialog 2>/dev/null` # If interactive, prompt for all parameters. Loop until user is # satisfied. # while $interactive; do if [ -x "$DIALOG" ]; then ask_pagetitle ask_language ask_owner_and_email ask_output ask_images ask_percentage ask_thumbnail_size ask_preamble ask_style ask_nav_links ask_grouping ask_xmplink if $DIALOG --backtitle "$d_backtitle" --yesno\ "Are these correct?\n\ Title = \"$pagetitle\"\n\ Language = \"$language\"\n\ Owner = \"$owner\"\n\ E-mail = \"$email\"\n\ Preamble = \"$preamble\"\n\ Style sheet = \"$style\"\n\ Up link = \"$up\"\n\ Prev link = \"$prevlink\"\n\ Next link = \"$nextlink\"\n\ Output = \"$output\"\n\ Group by = ${group:-(none)}\n\ XMP link = ${xmplink}" 18 72; then interactive=false fi else # No dialog, use read instead read -e -p "Page title? [$pagetitle] " [[ -z "$REPLY" ]] || pagetitle="$REPLY" read -e -p "Language? [$language] " [[ -z "$REPLY" ]] || language="$REPLY" read -e -p "Owner? [$owner] " [[ -z "$REPLY" ]] || owner="$REPLY" read -e -p "Preamble? [$preamble] " [[ -z "$REPLY" ]] || preamble="$REPLY" read -e -p "Style URL? [$style] " [[ -z "$REPLY" ]] || style="$REPLY" read -e -p "rel=up URL? [$up] " [[ -z "$REPLY" ]] || up="$REPLY" read -e -p "rel=prev URL? [$prevlink] " [[ -z "$REPLY" ]] || prevlink="$REPLY" read -e -p "rel=next URL? [$nextlink] " [[ -z "$REPLY" ]] || nextlink="$REPLY" read -e -p "Output file? ${output:+[$output]} " [[ -z "$REPLY" ]] || output="$REPLY" read -e -p "Images? [$images] " [[ -z "$REPLY" ]] || images="$REPLY" if [ -z "$output" ]; then echo echo "** Sorry, the output file must be specified." echo "** Use \"-\" if you want to print to standard output." echo else echo echo "Page title : $pagetitle" echo "Language : $language" echo "Owner : $owner" echo "Output : $output" echo "Preamble : \"$preamble\"" echo "Images : $images" echo "Style sheet : \"$style\"" echo "rel=up : \"$up\"" echo "rel=prev : \"$prevlink\"" echo "rel=next : \"$nextlink\"" echo read -e -p "Is this OK? [Y] " if [ "$REPLY" = "y" -o "$REPLY" = "Y" -o "$REPLY" = "" ];then interactive=false fi fi fi done # If a .htaccess file for Apache was requested, write or update it. if $htaccess; then [[ -f .htaccess ]] || touch .htaccess egrep -i '^[ ]*AddCharset[ ]+UTF-8[ ]+\.xmp\>' .htaccess ||\ echo 'AddCharset UTF-8 .xmp' >>.htaccess egrep -i '^[ ]*AddType[ ]+application/rdf\+xml[ ]+.xmp\>' .htaccess ||\ echo 'AddType application/rdf+xml .xmp' >>.htaccess fi # Redirect generated HTML output to file, unless it is "-" (stdout) [[ "$output" = "-" ]] || exec >"$output" # Create a temporary file to hold the text for the copyright COPYRIGHT=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." echo "Copyright © "`date +%Y`" $owner <$email>" >$COPYRIGHT RDFFILE=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." TMP2=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." TMP3=`mktemp -q $TEMPDIR/XXXXXX` || die "Cannot create temporary file." # Translate name of the language into an index into language array typeset -i lang ((lang = ${#languages[*]} - 1)) while [ "${languages[$lang]}" != "$language" -a $lang -gt 0 ]; do ((lang = $lang - 1)) done # Create the directories for the thumbnails and the reduced JPEGs [[ -d $thdir ]] || mkdir $thdir [[ -d $smdir ]] || mkdir $smdir # Write the header of the HTML file. output_header "$pagetitle" # Sort by series and by date if [ "$group" ]; then set -- $images echo -e "Sorting\c" >&2 for f; do echo -e ".\c" >&2 get_xmp "$f" >$RDFFILE case "$group" in series) echo -e `extract "$dcRelation" $RDFFILE\ | tr -s '\r\n\t' ' '`"\t$f" >>$TMP2;; year) echo -e `extract "$dcDate" $RDFFILE\ | tr -s '\r\n\t' ' '\ | sed -e 's/.*\([0-9][0-9][0-9][0-9]\).*/\1/'`"\t$f" >>$TMP2;; *) die "Bug! Cannot happen!";; esac done # New list of images, sorted by group images=`sort -b -d -f -s $TMP2 | cut -f2` # Make a menu of groups echo "
    " sort -b -d -f -u -t ' ' -k 1,1 $TMP2 | cut -f1 | cat -n | \ sed -e 's/^\( *[0-9]* \)@@@$/\1.../' \ -e 's/^ *\([0-9][0-9]*\) /
  • /' \ -e 's/$/<\/a>/' echo "
" echo >&2 fi # Print preamble, if any if [ -f "$preamble" ]; then echo "
" cat "$preamble" echo "
" fi # Loop over all arguments unset mainpage typeset -i groupcount=1 prevgroup=" " set -- $images first=${1%.[jJ][pP][gG]}.html last=${!#%.[jJ][pP][gG]}.html while [ $# -gt 0 ]; do prev="$mainpage" # For "prev" link f="$1" # Image to process if [ -z "$2" ]; then unset next else # Bug: assumes next image in same directory next=${2##*/} next=${next%.[jJ][pP][gG]}.html fi h=${f##*/} h=${h%.[jJ][pP][gG]} # Basename of original image mainpage="${h}.html" # HTML page for small image shift echo -e "Processing $f \c" >&2 g="$thdir/${h}" # Basename of thumbnail j="${g}.jpg" # Full name of thumbnail smallbase="$smdir/${h}" # Basename of 640x480 version smallname="$smallbase.jpg" # Full name of 640x480 version metalink="${f%.*}.xmp" # URL to the XMP data [[ $xmplink = dynamic ]] && metalink="$f;application%2Frdf%2Bxml" typeset -i size=`getsize "$f"` echo -e "(${size} KB), \c" >&2 # Check for XMP. The function get_xmp also makes the XMP file for the # image, if needed. get_xmp "$f" >$RDFFILE if test -s $RDFFILE; then has_xmp=true; else has_xmp=false; fi unset description title date place series number camera lens film \ develdate creator contributor rights latitude longitude if $has_xmp; then description=`extract "$dcDescription" $RDFFILE` title=`extract "$dcTitle" $RDFFILE` date=`extract "$dcDate" $RDFFILE` [[ "$date" ]] || date=`extract "$exifDateTimeOriginal" $RDFFILE` [[ "$date" ]] || date=`extract "$xapCreateDate" $RDFFILE` place=`extract "$dcCoverage" $RDFFILE` series=`extract "$dcRelation" $RDFFILE` number=`extract "$dcIdentifier" $RDFFILE` creator=`extract "$dcCreator" $RDFFILE` contributor=`extract "$dcContributor" $RDFFILE` rights=`extract "$dcRights" $RDFFILE` camera=`extract "$tcCamera" $RDFFILE` [[ "$camera" ]] || camera=`extract "$tiffModel" $RDFFILE` lens=`extract "$tcLens" $RDFFILE` film=`extract "$tcFilm" $RDFFILE` develdate=`extract "$tcDevelDate" $RDFFILE` latitude=`extract "$exifLatitude" $RDFFILE` longitude=`extract "$exifLongitude" $RDFFILE` if [ ! -z "$latitude" ]; then latitude=`minutes-to-dec "$latitude"`; fi if [ ! -z "$longitude" ]; then longitude=`minutes-to-dec "$longitude"`; fi fi if [ -z "$description" ]; then description=$number; fi if [ -z "$description" ]; then description=$h; fi # Generate small version, unless an up-to-date version already exists # Copy the XMP, if it exists, or add a standard copyright echo -e "small \c" >&2 if $has_xmp; then echo -e "http://ns.adobe.com/xap/1.0/\000\c" >$TMP3 cat $RDFFILE >>$TMP3 else cp $COPYRIGHT $TMP3 fi if [[ ! -f "$smallname" || "$f" -nt "$smallname" ]]; then # scale $smallwd $smallht <"$f" | wrjpgapp -cfile $TMP3 >"$smallname" scale $smallwd $smallht $TMP3 <"$f" >"$smallname" fi typeset -i smallsize=`getsize "$smallname"` echo -e "(${smallsize} KB), \c" >&2 # Generate thumbnail unless an up-to-date version already exists echo "thumbnail" >&2 if [[ ! -f "$j" || "$f" -nt "$j" ]]; then crop_and_scale $crop $w1 $w1 $smallname >$j fi fileinfo=`get_dimension <"$j"` thumbwd=`echo $fileinfo | cut -d' ' -f1` thumbht=`echo $fileinfo | cut -d' ' -f2` # Find out if $smallname is indeed smaller than $f. Store the name # and size of the smaller of the two in $mainname and $mainsize, and # compute the name of an HTML file $mainpage # if [ $smallsize -lt $size ]; then mainname="$smallname" mainsize=$smallsize else mainname="$f" mainsize=$size fi # Write an HTML page for the small version, with links to prev, next # and thumbnails and to the large image ( echo "" echo echo "" echo "" echo "" # Header echo -e "\c" if [ -z "$title" ]; then echo -e "$description\c"; else echo -e "$title\c"; fi echo "" [[ -z "$prev" ]] || echo "" [[ -z "$next" ]] || echo "" echo "" echo "" echo "" if [ ! -z "$email" ]; then echo -e "" fi $has_xmp && echo "" if [ -z "$style" ]; then cat <<-EOF EOF else echo "" fi echo # Body echo "" if [ -z "$prev" ]; then echo "" else echo "
" fi echo "" if [ -z "$next" ]; then echo "" else echo "" fi if $has_xmp; then echo "" fi echo echo -e "

\c" if [ -z "$title" ]; then echo -e "$descriptionf\c"; else echo -e "$title\c"; fi echo "

" echo echo "

\"${Image[$lang]}\""" echo echo "

$description" echo echo "" [[ -z "$date" ]] || echo "
${Date[$lang]}$date" [[ -z "$place" ]] || echo "
${Place[$lang]}$place" [[ -z "$series" ]] || echo "
${Series[$lang]}$series" [[ -z "$number" ]] || echo "
${Number[$lang]}$number" [[ -z "$creator" ]] || echo "
${Creator[$lang]}$creator" [[ -z "$contributor" ]] || echo "
${Contributor[$lang]}$contributor" [[ -z "$camera" ]] || echo "
${Camera[$lang]}$camera" [[ -z "$lens" ]] || echo "
${Lens[$lang]}$lens" [[ -z "$film" ]] || echo "
${Film[$lang]}$film" [[ -z "$develdate" ]] || echo "
${DevelDate[$lang]}$develdate" if [ "$osm_zoom" -ge 0 ]; then if [ ! -z "$latitude" ] && [ ! -z "$longitude" ]; then echo "
${Latitude[$lang]}$latitude ⚑" echo "
${Longitude[$lang]}$longitude ⚑" fi else if [ ! -z "$latitude" ] && [ ! -z "$longitude" ]; then echo "
${Latitude[$lang]}$latitude" echo "
${Longitude[$lang]}$longitude" fi fi [[ -z "$rights" ]] || echo "
${Rights[$lang]}$rights" echo "
${Size[$lang]}$size KB" echo "
" ) > "$mainpage" # If images are grouped, insert a group title, if needed case "$group" in series) h="$series";; year) h=`echo \"$date\"|sed -e 's/.*\([0-9][0-9][0-9][0-9]\).*/\1/'`;; *) h="$prevgroup";; esac if [ "$h" != "$prevgroup" ]; then [[ "$prevgroup" == " " ]] || echo "" echo echo "

" echo "

$h

" ((groupcount++)) prevgroup="$h" fi # Output the HTML code for the thumbnail. # Link it to page with the small image echo echo "
" echo "
" echo "

" echo "

" [[ -z "$title" ]] || echo "

$title

" echo "

" [[ -z "$number" ]] || echo " $number" echo " ${size} KB" # Don't link to the small version if the small version is actually larger if [ $smallsize -lt $size ]; then echo " ${smallsize} KB" else rm "$smallname" fi echo " " # ToDo: if the description (or any other field) is a URL, make a link echo " $description" # Add the number and the date (will only be visible when printed) [[ -z "$date" ]] || echo " $date" [[ -z "$place" ]] || echo " $place" # If the XMP data exists, make a URL that can retrieve it. if $has_xmp; then echo " RDF" fi echo "

" done [[ "$group" ]] && echo "
" output_footer # Local Variables: # mode: ksh # End: