3 # Purpose: create a tiny webgallery using CSS-features
4 # Authors: Wolfgang Scheicher <worf@grml.org>
5 # Bug-Reports: see http://grml.org/bugs/
6 # License: This file is licensed under the GPL v2.
7 ################################################################################
10 DISPLAY_GEOMETRY=640x480
11 THUMBNAIL_GEOMETRY=150x150
12 PREVIEW_GEOMETRY=250x250
15 PARENT_DIR="Übergeordnetes Verzeichnis"
17 PATH=$PATH:/usr/X11R6/bin:/usr/bin
26 THUMBNAILS=("$DISPLAY_GEOMETRY" "$THUMBNAIL_GEOMETRY")
27 FILE_EXTENSIONS=("jpg" "png" "gif")
28 REQUIRED=("jpegtran" "convert" "identify" "find" "tr" "sed" "awk" "grep")
30 ##############################################################
32 create_sample_config () {
33 # sample config with some default values
35 if [ -f description ] ; then
37 echo "description file allready exists!"
39 echo "creating example description file"
42 echo -e "# Gallery Config File\n#
43 # Title for this Directory
44 TITLE=\"${PWD##*/}\"\n
47 # this parameters affect the dir list in the parent directory:
49 THUMB=\"$(find_all_images | head -n 1 )\"\n
50 # Index to sort dirs by.
51 # You might want to use some date for chronological order
52 INDEX=\"$(date +%F)\"\n" > $DST
53 if [[ -z $STYLESHEET ]] ; then
55 # This will be used for all subdirs as well
56 STYLESHEET=\"stylesheet.css\"" >> $DST
60 ##############################################################
63 # create datadir and check for required apps
67 for app in "${REQUIRED[@]}" ; do
68 if which $app 2>/dev/null >/dev/null ; then
71 echo "ERROR: $app not found!"
75 if [[ -f description ]] ; then source "description"; fi
76 STYLESHEET=$( find_stylesheet )
80 # adds a "../ if it is not a absolute path or a url"
81 # otherwise returns the same string again
82 if [[ "${1::1}" == "/" ]] ; then
84 elif [[ "${1::7}" == "http://" ]] ; then
86 elif [[ ! -z $1 ]] ; then
92 # searches parent dirs recursively for a stylesheet
93 # until it reaches the root dir
94 if [[ -f description ]] ; then source "description"; fi
95 if [[ -z $STYLESHEET ]] ; then
96 if [[ ! "$PWD" == "/" ]] ; then
98 parent_dir $( find_stylesheet )
105 ##############################################################
108 # returns a list of all (supported) Images in the current dir
110 for ext in "${FILE_EXTENSIONS[@]}" ; do
111 find *.${ext} -maxdepth 0 2> /dev/null
116 # Searches all dirs and lists them,
117 # sorted by the INDEX field in the description file
119 DIRS="$(find * -maxdepth 0 -type d)"
120 for DIR in $DIRS ; do
122 if [[ -f ${DIR}/description ]] ; then source "${DIR}/description"; fi
123 echo "${INDEX} ${DIR}" )
124 done | sort | sed -e "s/^\S*\s//"
127 ##############################################################
130 # deletes old thumbnails and html files
131 # temporarily creates a filelist
133 if [[ "$RECURSIVE" == "true" ]] ; then
134 ALL_DIRS=( $(find_all_dirs) )
135 for DIR in "${ALL_DIRS[@]}"; do
136 ( IFS=$OLDIFS && cd "$DIR" && $0 $OPTS ; )
140 if [[ -d "${DATADIR}" ]] ; then
141 find_all_images > "${DATADIR}/filelist"
142 for GEOMETRY in "${THUMBNAILS[@]}"; do
144 [[ -d "${DATADIR}/${GEOMETRY}" ]] &&
145 cd "${DATADIR}/${GEOMETRY}" &&
147 awk 'NR==FNR {a[$0];next}
148 !($0 in a)' ../filelist - |
150 echo "rm ${DATADIR}/${GEOMETRY}/${line}"
157 find *.html -maxdepth 0 2> /dev/null |
158 awk 'NR==FNR {a[$0];next}
159 {sub(/\.html$/,"",$0)}
160 !($0 in a)' filelist - |
162 echo "rm ${DATADIR}/${line}.html"
166 rm "${DATADIR}/filelist"
170 ##############################################################
173 # generates thumbnails
174 # time of modification is set to that of the original and used
175 # to check if existing thumbs need updating
176 # orientation in the exif-header is used to rotate generated images
178 for GEOMETRY in "${THUMBNAILS[@]}"; do
179 mkdir -p "$DATADIR/$GEOMETRY" || exit
180 echo -ne "($GEOMETRY"
181 DST="$DATADIR/$GEOMETRY/$FILE"
183 if [[ -e $DST ]]; then
184 if [[ $(stat -c "%Y" $FILE) == $(stat -c "%Y" $DST) ]]; then
195 if [[ $SKIP == "false" ]]; then
197 ORIENTATION=$(identify -format "%[EXIF:Orientation]" "$FILE")
198 if [[ "$ORIENTATION" == "6" ]]; then
200 convert -quality $THUMBNAIL_QUALITY -rotate 90 -geometry "$GEOMETRY+0+0>" "$FILE" "$DST"
201 elif [[ "$ORIENTATION" == "8" ]]; then
203 convert -quality $THUMBNAIL_QUALITY -rotate 270 -geometry "$GEOMETRY+0+0>" "$FILE" "$DST"
206 convert -quality $THUMBNAIL_QUALITY -geometry "$GEOMETRY+0+0>" "$FILE" "$DST"
208 if [[ "${FILE##*.}" == "jpg" ]]; then
210 jpegtran -copy none -optimize -progressive "$DST" > "$DST.tmp"
211 mv -f "$DST.tmp" "$DST"
215 touch -m --reference=$FILE $DST
226 THUMBGEOMETRY=$(identify -format "%wx%h" "$DATADIR/$THUMBNAIL_GEOMETRY/${FILE}")
227 THUMBWIDTH=${THUMBGEOMETRY%x*}
228 THUMBHEIGHT=${THUMBGEOMETRY#*x}
230 THUMBT=$(((156 - $THUMBHEIGHT )/2 ))
231 THUMBB=$(((157 - $THUMBHEIGHT )/2 ))
232 THUMBL=$(((156 - $THUMBWIDTH )/2 ))
233 THUMBR=$(((157 - $THUMBWIDTH )/2 ))
236 COMMENT=$(identify -format "%c" "${FILE}" | tr '\n' ' ')
237 THUMBNAIL=$DATADIR/$THUMBNAIL_GEOMETRY/${FILE}
238 THIS_HTML=$DATADIR/${FILE}.html
240 html_header > ${THIS_HTML}
242 echo "<div class=\"gallerynav\">
243 ${FILE}
244 <a href=\"../index.html\">Index</a> <a href=\"${LAST}.html\"><<<</a> ${CURRENT}/${IMAGE_COUNT} <a href=\"${NEXT}.html\">>>></a>
249 <a href=\"../${FILE}\"><img alt=\"${DISPLAY_GEOMETRY}/${FILE}\" src=\"${DISPLAY_GEOMETRY}/${FILE}\" /></a>
253 identify -format "<table>
254 <tr><td>Auflösung:</td><td>%wx%h</td></tr>
255 <tr><td>Dateigröße:</td><td>%b</td></tr>
256 <tr><td>Camera:</td><td>%[EXIF:Model]</td></tr>
257 <tr><td>Datum/Zeit:</td><td>%[EXIF:DateTime]</td></tr>
258 <tr><td>Kommentar:</td><td>%c</td></tr>
259 </table>" ${FILE} >> $THIS_HTML
261 echo "</div>" >> $THIS_HTML
262 html_foot >> $THIS_HTML
264 echo "<a href=\"$THIS_HTML\"><img alt=\"Thumbnail\" src=\"$THUMBNAIL\" style=\"width:${THUMBWIDTH}px; height:${THUMBHEIGHT}px; margin: ${THUMBT}px ${THUMBR}px ${THUMBB}px ${THUMBL}px;\" title=\"${COMMENT}\" /><br />$FILE</a>" >> index.html
269 ##############################################################
272 # generates the upper part of the index page
273 # containing the list of subdirs
274 # which are recursively processed from here too
276 TITLE="${TITLE=${PWD##*/}}"
277 html_header > index.html
278 echo "<div class=\"cont\">" >> index.html
279 echo "<h1>${TITLE}</h1>" >> index.html
280 echo "<ul>" >> index.html
281 echo "<li class=\"back\"><b><a href=\"../index.html\">${PARENT_DIR}</a></b></li>" >> index.html
282 ALL_DIRS=( $(find_all_dirs) )
283 for DIR in "${ALL_DIRS[@]}"; do
284 ( TITLE="${DIR}"; THUMB=""; INDEX=""; COMMENT=""
285 if [[ -f ${DIR}/description ]] ; then source "${DIR}/description"; fi
286 echo "<li class=\"dir\"><a class=\"tooltip\" href=\"${DIR}/index.html\"><b>${TITLE}</b>" >> index.html
288 if [[ ! "${THUMB}${COMMENT}" == "" ]]; then
289 if [[ "${COMMENT}" == "" ]]; then
290 echo "<span><table><tr><td><img alt=\"Thumbnail\" src=\"${DIR}/${DATADIR}/thumb.${THUMB##*.}\" /></tr></table></span>" >> index.html
291 elif [[ "${THUMB}" == "" ]]; then
292 echo "<span><table><tr><td>${COMMENT}</td></tr></table></span>" >> index.html
294 echo "<span><table><tr><td><img alt=\"Thumbnail\" src=\"${DIR}/${DATADIR}/thumb.${THUMB##*.}\" /></td><td></td><td></td><td>${COMMENT}</td></tr></table></span>" >> index.html
297 echo "</a></li>" >> index.html
298 if [[ "$RECURSIVE" == "true" ]] ; then
299 ( STYLESHEET="$(parent_dir ${STYLESHEET})"
300 IFS=$OLDIFS && cd "$DIR" && $0 $OPTS ; )
307 <div class=\"gallery\">
308 <div class=\"spacer\"></div>
314 <div class=\"spacer\"></div>
318 html_foot >> index.html
321 ##############################################################
323 create_sample_stylesheet () {
324 if [ -f stylesheet.css ] ; then
325 echo "stylesheet.css allready exists!"
328 cat << EOF > stylesheet.css
329 a {text-decoration:none;}
331 div.gallery img {border: 2px inset #aaa; margin:3px;}
332 div.gallery a {color:#000; border: 2px outset #aaa; text-decoration:none; text-align:center; float:left; padding:3px; margin:4px; background-color:#ddd;}
333 div.gallery a:hover {color:#333; border: 2px outset #ccc; background-color:#eee;}
334 div.spacer {clear: both;}
335 div.gallerynav {text-align: center; margin: 0px; padding:0em 0.3em 0em 0.3em;}
337 a.tooltip, a.tooltip:link, a.tooltip:visited, a.tooltip:active { position: relative; }
338 a.tooltip span {display: none}
339 a:hover.tooltip span {display: block; position: absolute; top: 2.5em; left: 1.5em; z-index: 100; color: #000; padding: 3px; border:1px solid #000; background: #ffc; }
343 ##############################################################
348 <title>${TITLE}</title>
349 <link rel=\"stylesheet\" type=\"text/css\" href=\"${STYLESHEET}\" />
362 ##############################################################
365 # generates the whole thing, puts everything together
367 ALL_IMAGES=( $(find_all_images) )
368 IMAGE_COUNT=${#ALL_IMAGES[@]}
371 STYLESHEET="$(parent_dir ${STYLESHEET})"
375 for file in "${ALL_IMAGES[@]}" "../index" ; do
377 if [[ "$FILE" != "../index" ]]; then
383 CURRENT="$(( ${CURRENT} + 1 ))"
387 if [[ ! -z "${THUMB}" ]] ; then
388 echo -ne "preview thumbnail from ${THUMB}\t"
389 THUMBNAILS=("$PREVIEW_GEOMETRY")
391 [ -e "${DATADIR}/thumb.${THUMB##*.}" ] && mv "${DATADIR}/thumb.${THUMB##*.}" "${DATADIR}/${PREVIEW_GEOMETRY}/${THUMB}"
393 mv "${DATADIR}/${PREVIEW_GEOMETRY}/${THUMB}" "${DATADIR}/thumb.${THUMB##*.}"
396 ) | tee -a $LOG >> $VERBOSE
398 echo " $IMAGE_COUNT Image(s) in ${TITLE}"
401 ##############################################################
405 while getopts "vdsrp-:" OPT ; do
407 v) VERBOSE=/dev/stdout
409 d) create_sample_config
412 s) create_sample_stylesheet
421 echo -n "ERROR: Missing argument for option \"$OPTARG\". "
425 echo -n "ERROR: Unknown option \"$OPTARG\". "
430 shift $(($OPTIND -1))
432 build_gallery 2>${DATADIR}/errors
433 if [ -s ${DATADIR}/errors ]; then
434 echo -e "\nWARNING: there were errors. see .tmp/errors"
439 ## END OF FILE #################################################################