Newer
Older
webtls / img2www
@HIROSE Yuuji HIROSE Yuuji on 2 Jun 2018 28 KB git gateway started
#!/bin/sh
# Compose HTML files from Image files.
# $Id: img2www,v 1.49 2017/03/04 09:34:53 yuuji Exp yuuji $
# (c)1997-2014 by HIROSE Yuuji [yuuji>at<gentei.org]
#
# References:
#	http://www.hp-stylelink.com/news/2014/06/20140617.php
#	http://kudox.jp/java-script/javascript-gesture-event
#	https://developer.mozilla.org/ja/docs/Web/API/event

myname=`basename $0`

SCALE=0.2
SCALE="-xsize 60 -ysize 45"
dTH_X=320
INDEX=index.html
noindex=0
hrefstdout=0
init=0
nomini=0
# bg='bgcolor="white"'
bg='#ffc0cb' # pink
back=none
fg=black
TABLE=''
TB=0
TW=200
TW2=''
CNT=0
CJPEG=cjpeg
DJPEG=djpeg
CONVERT=convert
cssfile=img2www.css
paragraphmargin=0.5ex
formhead=''
formtail=''
perl=`which perl`
cgi2args="./cgi2args.cgi"
timesort=''
annotate=img2www.txt
anntmp=./img2www-$$.tmp
xbm2jpg='xbmtopbm|pgmtoppm rgbi:1/1/1|cjpeg'
movicon="movie-icon.jpg"
thumbclass=" class=\"${THUMBCLASS:-thumbnail}\""
eofm1="<!-- img2www end mark1 -->"
eofm2="<!-- img2www end mark2 -->"
exifpar=${JHEADPARAMS:-"^Camera model(| Name) *:
(Flash|Focus) (Mode|used|range) *:
AF Points
^Exposure(| (time|Program|bias|compensation)) *:
^Aperture *:
^Focal length.*equiv
ISO (equiv.)? *:
Lens Type *:
^White *Balance *:
^Image Tone"}
type jhead >/dev/null 2>&1 && useexif=1 && exifcmd=jhead
type exiftool >/dev/null 2>&1 && useexif=1 && exifcmd=exiftool
if [ "$useexif" -a -s ${HOME}/.img2www-exif ]; then
  exifpar=`cat ${HOME}/.img2www-exif`
fi
if type pamscale >/dev/null 2>&1; then
  pnmscale=pamscale
else
  pnmscale=pnmscale
fi

# Determine default 8bit code
case `locale|grep LC_CTYPE 2> /dev/null` in
  *[Ee][Uu][Cc][Jj][Pp]) jcode='e' ;;
  *[Uu][Tt][Ff]-8)	 jcode='w' ;;
esac
if nkf=`which nkf` 2>&1; then
  tojis="$nkf"
  to8bit="$nkf -$jcode"
else
  tojis=/usr/local/bin/nkf
  to8bit='/usr/local/bin/nkf -$to8bit'
fi
[ -x /usr/ucb/echo ] && PATH=/usr/ucb:$PATH
tnquant=cat			# サムネイルの減色はデフォルトなしにした

finalize () {
  rm -f $anntmp > /dev/null 2>&1
  echo Terminated. 1>&2
  exit 0
}

while [ $# -ne 0 ];
do
    case "$1" in
	-s)     shift;  SCALE=$1 ;;
	-4)	SCALE="-xsize 48 -ysize 36" ;;
	-6)	SCALE="-xsize 60 -ysize 45" ;;	# これをデフォルトにした
	-9)	SCALE="-xsize 96 -ysize 72" ;;
	-1)	SCALE="-xsize 120 -ysize 80" ;;
	-ix)	shift;  INDEX=$1 ;;
	-n)	noow=1 ;;			# 処理済みならスキップ
	-ni)	noindex=1 ;;			# index.htmlを作らない
	-batch)	hrefstdout=1 ;;			# リンクのみを標準出力へ
        -pro*)	progress=1 ;;			# 処理中ファイルを出力
	-nm)	nomini=1 ;;			# mini作成をスキップ
	-t)	TABLE='   ' ;;			# <table>モード
	-tb)	shift; TB=$1 ;;			# <table>の border
	-tw)	shift; TW=$1 ;;			# <table>左側のWIDTH
	-tw2)	shift; TW2=$1 ;;		# <table>右側のWIDTH
	-T)	TABLE='   '
		SCALE="-xsize 120 -ysize 90" ;; # table御気楽バージョン
	-time|-ts) timesort=1 ;;		# 時刻順ソート
	-js)	usejs=1 ;;			# jsで画像移動
	-sf)	usejs=1; usest=1 ;;		# 固定領域ブラウザ+float
	-sx)	usejs=1; shift; dTH_X=$1 ;;	# 固定領域の幅
        -tq)	shift; tnquant="ppmquant $1 2>/dev/null" ;;
	-bg)	shift; bg="$1" ;;
	-back)	shift; back="url($1)" ;;
	-fg)	shift; fg="$1" ;;
	-h)	shift; heading="$1" ;;		# htmlの最初のH1
	-css)	shift; cssfile="$1" ;;
	-pm)	shift; paragraphmargin="$1" ;;
	-an)	shift; annotate="$1"	;;	# annotateファイル名
	-na)	annotate=''		;;	# annotateなし
	-tj)	shift; tojis="$1"	;;
	-te)	shift; to8bit="$1"	;;
	-nj)	tueoc='cat' tojis='cat' ;;
	-ex)	shift; exifcmd="$1"	;;
	-to)	shift; toaddress="$1" ;;
	-me)	shift; maintainer="$1" ;;
	-order)
	  if [ -x $cgi2args ]; then
	    formhead="<form method=\"GET\" action=\"$cgi2args\">
あなたのメイルアドレス: <input name=\"email\" size=\"40\" maxlength=\"40\"><br>
<input type=\"hidden\" name=\"execcmd\" value=\"./order.pl\">
<input type=submit value=\"注文\"><input type=reset value=\"やり直し\">"
	    formtail="</form>"
	    TABLE='   '				# -T と揃えること
	    SCALE="-xsize 120 -ysize 90"
	  else
	    echo "カレントディレクトリに cgi2args.cgi が必要です."
	    echo "(http://www.gentei.org/~yuuji/software/ にあるよ)"
	  fi
	  ;;
	*)
		if [ -s "$1" ]; then
			files="$files $1"
		fi ;;
    esac
    shift
done
xsize=`expr "z$SCALE" : '.*-xsize \(.*\) -.*'`
ysize=`expr "z$SCALE" : '.*-ysize \(.*\)'`
if [ "$usejs" ]; then
 TH_X=$dTH_X; TH_Y=`expr 0$TH_X \* 3 / 4`
else
 TH_X=$xsize; TH_Y=$ysize
fi


if [ "$files" = "" ]; then
	cat<<_EOU_
なんかファイルを指定してね。
$myname はjpgファイルまたは動画ファイルをががっと読み込んで、
サムネイルファイルを作りそれらを<img src..>で読み込んだ index.html
を作ります。サムネイルをクリックすると元の大きなjpgが出るようなリンクを
張ってくれます。指定したファイルが動画の場合は、動画の先頭フレームの
静止画像へのリンクと、動画本体へのリンクを張ります(要mplayer)。

またカレントディレクトリに $annotate というファイルを作り、その中に
ファイル名,	ALT文字列,	説明コメント
という行をたくさん書いておくと img src のALT属性、画像HTMLにつける
コメント文をそこから引っ張って来て書き込んでくれます。

$myname の使い方:
   $myname [オプション] *.jpg *.avi ...
   オプションは以下の通り(括弧内はデフォルト値)
	-4		-s "-xsize 48 -ysize 36" と同じ
	-6		-s "-xsize 60 -ysize 45" と同じ
	-9		-s "-xsize 96 -ysize 72" と同じ
	-1		-s "-xsize 120 -ysize 90" と同じ
	-ni		index.html を作らない(No Index)
	-ts 又は -time	対象ファイルを時刻順に並べ換えてから処理
	-t		table環境として吐き出す
	    -tb	数	tableのborder(デフォルト=0)
	    -tw	数	tableの左側(写真部分)の幅($TW)
	    -tw2 数	tableの右側(文章部分)の幅(${TW2:-"無指定"})
	-T		-t -1 同時指定の御気楽オプション
	-js		画像移動をjsで
	    -sf		  動的HTMLモード
	    -sx	幅	  動的HTMLモードの右上写真ステージの幅($dTH_X)
	-bg		htmlファイルのbgcolor指定
	-back		htmlファイルのbackground指定
	-fg		htmlファイルのtext色指定
	-h 見出し	htmlファイルの最初のh1見出し
	-css		css定義ファイル名($cssfile)
	-pm		cssに定義するパラグラフの上下マージン($paragraphmargin)
	-an ファイル名	[画像, ALT文, コメント] を入れたファイル名($annotate)
	-tj コマンド	JIS変換するコマンド名($tojis)
	-na		$annotate を無視する
	-tq 色数	サムネイルを減色する
	-order		写真注文フォームを生成する 以下の2オプションと併用
	    -to	ADDR	注文受信者のemailアドレスをADDRに指定
	    -me ADDR	注文受理ページの管理者のアドレスをADDRに指定

$myname には netpbm と jpeglib(djpeg)が必要です。Unix上で画像処理をするには
欠かせないツールなので絶対にインストールしましょう。
_EOU_
	exit 0;
fi

catimg () {
    case $1 in
      *.jpg|*.jpeg|*.JPG)
	$DJPEG $1 ;;
      *.png|*.PNG)
        $CONVERT $1 PNM:- ;;
    esac
}

readcomment () {
    case $1 in
      *.jpg|*.jpeg|*.JPG)
	rdjpgcom $1 ;;
      *.png|*.PNG)
        identify -ver $1 | awk '/Comment:/{print $2}' ;;
    esac
}

mkjheadtable () {
  echo "<table class=\"exif\">"
  $exifcmd $1 | egrep -i -- "$exifpar" | grep -v ' or ' | uniq -u \
    | while IFS=: read x y; do
    echo "<tr><th>$x</th><td>$y</td></tr>"
  done
  echo "</table>"
}
[ $useexif ] || mkjheadtable() { :; }

iout=5 aout=6
if [ $noindex -eq 0 ]; then
  exec 5>> $INDEX
else
  exec 5> /dev/null
fi
if [ $hrefstdout -eq 1 ]; then
  exec 6>&1
else
  exec 6>&$iout
fi
##if [ $noindex -eq 0 ]; then
title=${TITLE:-${heading:-No Title}}
if true; then
	[ -s $INDEX ] && tail -1 $INDEX|fgrep -- "$eofm2">/dev/null && {
	  tailer=`sed -n "/$eofm1/,/$eofm2/p" $INDEX`
	  printf "/mark1/,\$d\nwq\n" | ed $INDEX >/dev/null
	  init=2
	}
	if [ ! -s $INDEX ]; then
	  init=1
	  cat>&$iout<<EOF
<html>
<head><title>$title</title>
<link rel="stylesheet" type="text/css" href="$cssfile">
<meta name="viewport" content="width=device-width, initial-scale=1" />
${usest:+<script language='JavaScript' src='img2www.js'>}
${usest:+</script>}
</head>

<body>
${usest:+<div id='stage'> </div>}
<div id="index">
${usest:+<div id='bstage'> </div>}
<h1>${heading:-Photo List}</h1>
<p id='eusage'>Hover onto or click thumbnails.</p>
<p id='usage'>${usest:+サムネイルにマウスを合わせると右上に大きめ表示、}
サムネイルをクリックすると単独表示になります。</p>
<p class="shadow-"> <!-- class="shadow" にすると写真白枠に -->
EOF
	fi
	[ "$TABLE" ] && echo "$formhead<table border=\"$TB\">"|$tojis >&$iout
fi
if [ "$timesort" ]; then
    files=`ls -tr $files`
fi

getannotate () {
    n=`grep -v "^[ 	]*#" $annotate|grep ",.*,"|wc -l`
    l=1
    $to8bit $annotate \
	| grep -v '^[ 	]*#' \
	| grep ',.*,' \
	| while read line; do
	printf '\r%s' "$l/$n" 1>&2
	l=`expr $l + 1`
	alt='' cmt=''
	eval `echo "$line" | sed 's/\([^,]*\),\(.*\)/f="\1" a="\2"/'`
	if [ -f $f -a "$a" ]; then
	    f=`echo $f|sed -e 's/\..*//' -e 's/-/_/'`
	    eval `echo "$a" | sed 's/\([^,]*\),\(.*\)/alt="\1" cmt="\2"/'`
	fi
	echo "alt$f () {
cat<<_EOF_
$alt
_EOF_
}"
	echo "cmt$f () {
cat<<_EOF_
$cmt
_EOF_
}"
    done 
    echo  1>&2
}

mkicon() {
  # $1=icon-directory
 (
  dir="$1"
  icon="$dir/$movicon"
  [ -s "$icon" ] && return
  # if icon not ready, make it
  cat<<EOF |eval "$xbm2jpg" >$icon
#define camera_width 39
#define camera_height 31
static char camera_bits[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 
  0xF0, 0x01, 0x00, 0xC0, 0x7F, 0xFC, 0x07, 0x00, 0xE0, 0xFF, 0xFE, 0x0F, 
  0x00, 0xE0, 0xFF, 0xFE, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0xF0, 
  0xFF, 0xFF, 0x1F, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0xF0, 0xFF, 0xFF, 
  0x1F, 0x00, 0xF0, 0xFF, 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0xFE, 0x0F, 0x00, 
  0xE0, 0xFF, 0xFE, 0x0F, 0x00, 0xC0, 0x7F, 0xFC, 0x07, 0x00, 0x00, 0x1F, 
  0xF0, 0x01, 0x02, 0xC0, 0xFF, 0xFF, 0x07, 0x03, 0xC0, 0xFF, 0xFF, 0xC7, 
  0x03, 0xC0, 0xFF, 0xFF, 0xE7, 0x03, 0xC0, 0x01, 0x00, 0xF7, 0x03, 0xC0, 
  0x01, 0x00, 0xFF, 0x03, 0xC0, 0x01, 0x00, 0xFF, 0x03, 0xC0, 0x01, 0x00, 
  0xFF, 0x03, 0xC0, 0x01, 0x00, 0xFF, 0x03, 0xC0, 0x01, 0x00, 0xF7, 0x03, 
  0xC0, 0x01, 0x00, 0xE7, 0x03, 0xC0, 0xFF, 0xFF, 0x87, 0x03, 0xC0, 0xFF, 
  0xFF, 0x07, 0x03, 0xC0, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
EOF
 )
}

mkmovlink() {
  # $1=movie-file(full-path) $2=thumbnail-file(basename)
  (mkicon `dirname "$1"`
   tmp1="$myname-tmp1"
   tmp2="$myname-tmp2"
   newicon=`echo $2|sed 's/sn_//'`
   link=`basename "$1"`
   icon="$movicon"

   sz=`BLOCKSIZE=k du -s "$1"`
   sz="`expr "$sz" : '\([0-9][0-9]*\)'`KB"
   wline=`catimg "$2" | pnmfile -`
   width=`expr "x$wline" : '.* \([0-9]*\) by'`
   height=`expr "x$wline" : '.* by \([0-9]*\)'`

   icw=`expr $width / 2` ich=`expr $height / 2`
   catimg "$movicon" | $pnmscale -xsize $TH_X -ysize $$TH_Y > $tmp2 2>/dev/null
   ## catimg "$movicon" | pnmscale -xsize $icw -ysize $ich > $tmp2 2> /dev/null

   # create link image
   trap "rm -f $tmp1 $tmp2" INT TERM
   if catimg "$2" | pnmpaste $tmp2 -$icw -$ich > $tmp1
   then
     cjpeg $tmp1 > "$newicon"
     icon="$newicon"
   fi > /dev/null 2>&1
   rm -f $tmp1 $tmp2
   trap INT TERM
  
   cat<<EOF
<a href="$link"><img src="$icon" alt="MOVIE"
$minisize align="middle">($sz)
EOF
   )
}

mksnap() (
  tmp1=00000001.jpg tmp2=00000002.jpg
  dir=`dirname "$1"`
  base=`basename "$1"`
  root=`expr "$base" : '\(.*\)\..*'`
  snap="sn_$root.jpg"
  (cd "$dir"
   mplayer -frames 1 -vo jpeg $base
   rm -f $tmp2
   mv -f $tmp1 $snap) > /dev/null 2>&1
  echo "$dir/$snap"
)

# Check img2www.txt
if [ -n "$annotate" -a -s $annotate ]; then
    echo Reading $annotate... 1>&2
    # Use temporary file because eval in pipeline takes no effect to
    # the current shell environment
    trap "finalize" INT TERM
    getannotate > $anntmp
    trap  INT TERM
    . $anntmp
    rm -f $anntmp
    echo Done
else
    getalt() {
	echo Photo
    }
    getcomment() {
	echo 'この行を消してここにコメント
左寄せが良ければ <p class="l"> に変える' \
	| sed -e 's/^/<!-- /' -e 's/$/ -->/' # | $tojis
    }
fi
getalt() (
	f=`echo $1|sed -e 's/\..*//' -e 's/-/_/'g`
	# echo eval "echo \$alt$f" 1>&2
	# eval "alt=\"\$alt$f\""
	if type alt$f >/dev/null 2>&1; then
	  #eval "alt=\"`alt$f`\""
	  alt$f
	else
	#echo "${alt:-Photo}" | $tojis
	  echo Photo
	fi # | $tojis
)
getcomment() (
	f=`echo $1|sed -e 's/\..*//' -e 's/-/_/g'`
	eval "cmt=\"\$cmt$f\""	# set by autoimg
	if type cmt$f >/dev/null 2>&1; then
	  cmt$f
	  #eval "cmt=\"`cmt$f`\""
	elif [ "$cmt" ]; then
	  echo $cmt
	else
	  echo 'この行を消してここにコメント
左寄せが良ければ <p class="l"> に変える' \
            | sed -e 's/^/<!-- /' -e 's/$/ -->/'
	fi # | $tojis
)

htmlname() (
  b=`basename $1|sed 's/\(.*\)\..*/\1/'`
  echo `dirname $1`"/$b.html"
)
[ x"$usejs" = x"" ] || {
  jsinit=" onload=\"init();\""
  jsstage=${usest:+" onMouseOver=\"stage(event);\""}
}
do_file() (
	i="$1"
	prev="$2"
	next="$3"
	minibase=`basename $i|sed 's/\(.*\)\..*/\1/'`
	minifile=`dirname $i`"/tn_${minibase}.jpg"
	html=`dirname $i`"/$minibase.html"
	imglink=`basename $i`
	if [ "$noow" -a -f $html -a -f $minifile ]; then
	    echo Skipping $i
	    return
	fi
	# echo mini=$minibase, mf=$minifile
	alt=`getalt $i`
	if [ "$alt" = "" ]; then
	    title=`readcomment $i`
	    if [ "$title" = "" ]; then
		title="$i"
	    fi
	else
	    title=`readcomment $i`
	    if [ x"$title" = x"" ]; then
		title="$alt"
	    else
		title="$title - $alt"
	    fi
	fi
	# get image size in pixel
	size=`catimg $i|pnmfile -| \
	 sed 's/[^0-9]*\([1-9][0-9]*\) by \([0-9]*\).*/width="\1" height="\2"/'`
	origx=`expr "$size" : '.*width=\"\([0-9]*\)".*'`
	origy=`expr "$size" : '.*height=\"\([0-9]*\)".*'`
	if [ $origx -gt $origy ]; then	# Landscape
	  scaleopt="-xsize"
	  minix=$xsize
	  miniy=`echo $minix \* $origy / $origx | bc -l | sed 's/\..*//'`
	  minisize="width=\"$minix\" height=\"$miniy\""
	else				# Portrait
	  scaleopt="-ysize"
	  # miniy=$xsize		# set height to width of landscape
	  miniy=$ysize			# set height to the same as landscape
	  minix=`echo $miniy \* $origx / $origy | bc -l | sed 's/\..*//'`
	  minisize="width=\"$minix\" height=\"$miniy\""
	fi
	if [ ! -f $minifile -o $nomini -eq 0 ]; then
	  newx=$TH_X
	  catimg $i | $pnmscale $scaleopt $newx |\
	    eval $tnquant |\
	    $CJPEG -progressive > $minifile
	    
	fi
	#minisize=`$DJPEG $minifile|pnmfile -| \
	# sed 's/[^0-9]*\([1-9][0-9]*\) by \([0-9]*\).*/width="\1" height="\2"/'`
	if [ "$TABLE" ]; then
	  echo " <tr>"			>&$iout
	  echo "  <td width=\"$TW\">"		>&$iout
	fi
	echo "$TABLE<a href=\"$html\">"	>&$aout
	echo "$TABLE<img$jsstage src=\"$minifile\" alt=\"$alt\"">&$aout
	echo "$TABLE      $minisize$thumbclass></a>" >&$aout
	if [ "$TABLE" ]; then
	  echo "  </td>"			>&$iout
	  CNT=`expr $CNT + 1`
	  echo "	<td${TW2:+ width=\"$TW2\"}>"	>&$iout
	  if [ "$formhead" ]; then
	    echo "	<input type=checkbox name=\"$i\">$i" >&$iout
	  else 
	    echo "	 $title<br>"		>&$iout
	    echo "	 コメントその$CNT"|$tojis>&$iout
	  fi
	  echo "	</td>"			>&$iout
	  echo " </tr>"			>&$iout
	fi
	case "$imglink" in
	  sn_*)
	    mkmovlink "$mov" "$minifile"	>&$iout
	    ;;
	esac
	cat>$html<<EOF
<html>
<head><title>$title</title>
<link rel="stylesheet" type="text/css" href="$cssfile">
${usejs:+<script language='JavaScript' src='img2www.js'>}
${usejs:+</script>}
</head>
<body>
EOF
	(
	link="    ${usejs:+        }"
	if [ "$prev" ]; then
	  phtml=`htmlname $prev`
	  link="<a id=\"prev\" href=\"$phtml\" onclick=\"moveHrefID('prev'); return false;\">PREV${usejs:+(S-Left)}</a>"
	fi
	printf '%s' "<pre>$link | "
	printf '%s' "<a href=\"index.html\">INDEX</a> | "
	link="    ${usejs:+         }"
	if [ "$next" ]; then
	  nhtml=`htmlname $next`
	  link="<a id=\"next\" href=\"$nhtml\" onclick=\"moveHrefID('next'); return false;\">NEXT${usejs:+(S-Right)}</a>"
	fi
	printf '%s' "${link}"
	echo "${usejs:+ || S-Dwn(shrink) S-UP(enlarge)}"
	printf '%s' "<span id=\"info\"> </span>"
	echo "</pre>"
	)					>>$html
	cat>>$html<<EOF
<p class="c shadow">
<img id="x"$jsinit src="$imglink" alt="$alt" $size>
</p><p class="c">
`getcomment $i`
</p>
<hr>
`mkjheadtable $imglink`
</body>
</html>
EOF
)

set $files
previ=''
nfiles=$#
for i
do
	nexti="$2"
	case $i in
	    # *.gif)		# No more GIF!!
	    # cat=giftopnm ;;	# No more Unisys!!!
	    tn_*|*mini*)
		echo "Skipping $i"
		continue ;;
	    sn_*)	;; # skip snapshot
	    *.mov|*.avi|*.mpg|*.rm)
		mov="$i"
		i=`mksnap $i` ;;
	    *.jpg|*.jpeg|*.JPG)
		cat=djpeg ;;
	esac
	do_file $i "$previ" "$nexti"
	if [ "$progress" ]; then
	  nfiles=`expr $nfiles - 1`
	  printf "$nfiles "
	fi
	previ="$i"
	shift
done

cssfile="`dirname $i`/$cssfile"
mkcss() {
  bptop="${usest+25}0px"
  index="${usest:+inde}x"
  itop="${usest:+0px}"
  itop="${itop:-${TH_Y}px}"
  pemx=`expr ${TH_X} + 15`
  pemy=`expr ${TH_Y} + 15`
#body {overflow: hidden; padding-top: $bptop;}
#html > body {overflow: auto; padding-top: 0;}
  cat>$cssfile <<EOF
body {background: $bg;}
div#stage {
  position: absolute; top: 0; right: 0;
  width: ${TH_X}px; height: ${TH_Y}px; border: 3px double #44a;
  padding: 5px; text-align: center;
  background: white;
  margin-right: 0; margin-left: auto;
  z-index: 2;
}
div#bstage {
  margin-right: 0; margin-left: auto; width: ${pemx}px; height: ${pemy}px;
  float: right;
}
body > div#stage {position: fixed;}
div#$index {
  position: static; height: 100%; padding-top: $itop;
  overflow: auto;
  z-index: 1;
}
body>div#$index {position: absolute; padding-top: 0; top: $itop; height: auto;}
img {vertical-align: top;}
p.c {text-align: center;}
table.exif {float: left;}
table.exif, table.exif * {
  font-size: 95%; border: 1px solid black; border-collapse: collapse;
  margin-right: 1em; background: #eef;
}
table.exif th {text-align: left;}
table.exif td {padding: 0.1ex 0.5ex;}
table.exif+p+* {clear: both;}
img.thumbnail {border: silver 3px outset;}
/* サムネイルを影つき写真の場合はコレ p class="shadow" で括ればよい。 */
img.shadow, *.shadow img {
	border: white 3px solid; box-shadow: black 3px 3px 3px;
	margin-right: 3px; margin-bottom: 3px;
}
EOF
}
mkcss

: <<EOF
(defun img2www-savejs (file)
  (interactive "fSave JavaScript to file: ")
  (save-excursion
    (save-restriction
      (widen)
      (goto-char (point-min))
      (re-search-forward "^MSIE" nil t)
      (write-region
       (match-beginning 0)
       (progn (re-search-forward "^EOF" nil t) (match-beginning 0))
       file))))
EOF

jsfile="`dirname $i`/img2www.js"
mkjs() {
  cat>$jsfile<<\EOF
MSIE = navigator.userAgent.indexOf("MSIE")!=-1;
Safari = navigator.userAgent.indexOf("Safari")!=-1;
document.onkeypress = keyExec;
if (Safari) document.onkeydown = keyExec;
self.focus();

function getKEYCODE(e){  

  if (document.getElementById && !MSIE )  
    return  e.charCode||e.keyCode;
  else if(document.all)       return  event.keyCode;
  else if(document.layers)    return  e.which;
}
function getimg() {
  return document.getElementById("x");
}
function replMag(link, mag) {
  if (!link) return;
  var orig = link.getAttribute("href");
  var argp = orig.indexOf("?");
  if (argp != -1) orig = orig.substring(0, argp);
  link.setAttribute("href", orig+"?"+pcnt+"%25");
}
function setImgSize() {
  var obj = getimg();
  obj.style.width = imgx*pcnt/100;
  obj.style.height = imgy*pcnt/100;
  // Update PREV/NEXT Links
  replMag(document.getElementById("prev"), pcnt);
  replMag(document.getElementById("next"), pcnt);
  var info = document.getElementById("info");
  if (!info) return;

  var mg = document.getElementById("mag");
  mg.innerHTML = pcnt+"% "
}
function setClickHandler(obj, hdString) {
  obj.setAttribute("onclick", hdString);
  if (MSIE) obj.onclick = new Function(hdString);
}
function createBTN() {
  var sp = document.getElementById("resizebtn");
  if (sp)
    return sp;
  var mag = document.createElement("span");
  mag.setAttribute("id", "mag");
  mag.innerHTML = pcnt+"% "
  var b1 = document.createElement("button");
  setClickHandler(b1, "fitWin();")
  b1.innerHTML = "fitToWindow";
  var b2 = document.createElement("button");
  setClickHandler(b2, "setWidth(400);")
  b2.innerHTML = "400";
  var b3 = document.createElement("button");
  setClickHandler(b3, "setWidth(640);")
  b3.innerHTML = "640";
  var b4 = document.createElement("button");
  setClickHandler(b4, "setWidth(800);")
  b4.innerHTML = "800";
  var b5 = document.createElement("button");
  setClickHandler(b5, "set100();")
  b5.innerHTML = "100%";
  var b6 = document.createElement("button");
  setClickHandler(b6, "shrink();")
  b6.innerHTML = "-10%";
  var b7 = document.createElement("button");
  setClickHandler(b7, "enlarge();")
  b7.innerHTML = "+10%";
  sp = document.createElement("span");
  sp.setAttribute("id", "resizebtn")
  sp.appendChild(mag);
  sp.appendChild(b1);
  sp.appendChild(b2);
  sp.appendChild(b3);
  sp.appendChild(b4);
  sp.appendChild(b5);
  sp.appendChild(b6);
  sp.appendChild(b7);
  return sp;
}
function frameWidth() {
  return document.getElementsByTagName("body")[0].offsetWidth;
  // setWidth(window.innerWidth);
}
function frameHeight() {
  return window.height ||
    (document.body&&document.body.clientHeight) ||
    (document.documentElement&&document.documentElement.clientHeight) ||
    480;
}
function setWidth(x) {
  var r = 100*x/imgx;
  pcnt = Math.floor(r);
  setImgSize();
}
function setHeight(y) {
  var r = 100*y/imgy;
  pcnt = Math.floor(r);
  setImgSize();
}
function fitWin() {
  var img = getimg()
  var w = frameWidth();
  var h = frameHeight()-(img.offsetTop||60);
  if (1.2 * getimg().getAttribute("width") > w)
    setWidth(w);
  if (getimg().getAttribute("height") > h)
    setHeight(h);
}
function shrink() {
  init();
  if (pcnt > 10) {
    pcnt -= 10;
    setImgSize();
    if (MSIE) window.scrollTo(0, 0);
  }
}
function set100() {
  pcnt=100;
  setImgSize();
}
function enlarge() {
  init();
  if (pcnt < 100) {
    pcnt += 10;
    setImgSize();
  }
}
function moveHrefID(id) {
  var cur = location.pathname;
  var file = cur.substring(cur.lastIndexOf("/")+1);
  var next = document.getElementById(id);
  if (!next) return;
  next = next.getAttribute("href");
//alert(next);
  if (pcnt != 100 && next.indexOf("?") == -1)
    next = next + "?"+pcnt+"%";
  location.replace(next);
  //location.href = next;
  img = getimg();
  img.setAttribute("onLoad", "init();");
  img.onload = "init();"
  return;
  alert(pcnt);
  //setImgSize();
  obj = getimg();
  obj.style.width = imgx*pcnt/100;
  obj.style.height = imgy*pcnt/100;

}

function keyExec(e) {
  key = getKEYCODE(e);
  mods = null;
  // if (!MSIE) mods = e.shiftKey|e.ctrlKey|e.altKey;
//alert(e.shiftKey)
  if (!MSIE) mods = e.shiftKey|e.ctrlKey|e.altKey;

  //d=new Date();
  // alert(e.type+", "+d.getSeconds())
  switch (key) {
  case 40: case 63233:		// down
    if (e.shiftKey)
      shrink();
    break;
  case 38: case 63232:		// up
    if (e.shiftKey) enlarge();
    break;
  case 37: case 63234:		// left
    if (e.shiftKey) moveHrefID("prev");
    break;
  case 39: case 63235:		// right
    if (e.shiftKey) moveHrefID("next");
    break;
  default:
    numericarg = 0;
  }
  return;
}

function removeAllChild(obj) {
  cs = obj.childNodes;
  var element_node = obj.nodeType;
  var i=0;
  while (i<cs.length) {
    if (cs[i].nodeType == element_node) {
      obj.removeChild(cs[i]);           // remove したらiはそのままでよい
    } else {
      i++;
    }
  }
}

/* 要らないはず
function adjIdx() {
  //Adjust #index's height
  var stageHeight = document.getElementById("stage").offsetHeight;
  var idx;
  var height = (MSIE ? document.body.clientHeight : innerHeight);;
  var indexHeight = (idx=document.getElementById("index")).offsetHeight;
  if (height-stageHeight > indexHeight) {
    idx.style.height = height-stageHeight;
  }
}
*/
function getCSSproperty(element, prop) {
  // http://www.quirksmode.org/dom/getstyles.html
  if (element.currentStyle)
     return element.currentStyle[prop];
  if (window.getComputedStyle)
     return document.defaultView.getComputedStyle(element, null).getPropertyValue(prop);
  return null;
}

var lastelement, lastX;
function stage(ev) {
  me = MSIE ? ev.srcElement : ev.target;
  if (me == lastelement || lastX == ev.screenX) return;
  var src = me.getAttribute("src");
  var stg = document.getElementById("stage");
  var stx = stg.style.width || parseInt(getCSSproperty(stg, "width")) ||
	/* There's no way to get effective element's width on `Safari 1.3'.
	 * So use offsetWidth for Safari.
	 *  -20 is ugly workaround for padding */
            stg.offsetWidth-20 || 320;
  var sty = parseInt(getCSSproperty(stg, "height") || stx*.75);
  stg.style.display = 'block';

  removeAllChild(stg);
  climg = document.createElement("img");
  climg.setAttribute("src", me.getAttribute("src"));
  var newst = stg.appendChild(climg);
  
  var ox = me.getAttribute("width");
  var oy = me.getAttribute("height");
  newst.style.height=sty;
  newst.style.width= oy ? sty/oy*ox : stx;

  lastelement = me;
  lastX = ev.screenX;
  /* adjIdx(); */
  //document.getElementById("index").style.height = "auto";
}

var imgx=0, imgy;
var pcnt = 100;
function init() {
  if (imgx == 0) {
    var img=getimg();
    imgx = parseInt(img.width);
    imgy = parseInt(img.height);
    // alert(location.href)
    if (!document.getElementById("button")) {
      var info = document.getElementById("info");
      if (info) info.appendChild(createBTN());
    }
    if (MSIE) {
      var b = document.getElementsByTagName("body")[0];
      b.onkeydown = new Function("keyExec(event);");
    }
    if (location.href.match(/(.*)\?(\d+)%/) && imgx > frameWidth()) {
      pcnt = parseInt(RegExp.$2);
      setImgSize();
    } else {
      fitWin();
    }
  }
}

window.addEventListener("load", function(event) {
    var touchStartX;
    var touchMoveX;
    var swThreshold=3*window.screen.width/5;

    if (! "ontouchstart" in window) return;
    var stg = document.getElementById("stage");
    if (stg) {
	var body = document.getElementsByTagName("body")[0];
	var usage = document.getElementById("usage");
	var eusage = document.getElementById("eusage");
	body.addEventListener("touchstart", function(event) {
	    stg.style.display = "none";
	    if (usage) usage.innerHTML =
		"サムネイルをタップすると画像単独表示へ。\
単独表示で画像を大きく左(右)にスワイプすると次(前)の画像に移ります。"
	    if (eusage) eusage.innerHTML =
		"Tap thumbnail to show large image. \
In large-image mode, swipe image left(right) widely to go to the \
next(previous) image."
	}, false)
	return;
    }
    var img = getimg();
    if (img == null) return;
    img.addEventListener("touchstart", function(event) {
	touchStartX = event.touches[0].screenX;
    }, false);

    // touchmove event
    img.addEventListener("touchmove", function(event) {
	if (event.changedTouches.length > 1) {
	    touchStartX = null;
	    return;
	}
	touchMoveX = event.changedTouches[0].screenX;
    }, false);

    // touchEnd
    img.addEventListener("touchend", function(event) {
	if (!touchStartX) return;
	if (touchStartX > touchMoveX) {
	    if (touchStartX > (touchMoveX + swThreshold)) {
		// from RIGHT to LEFT
		img.style.opacity = 0.3;
		moveHrefID('next');
	    }
	} else if (touchStartX < touchMoveX) {
	    if ((touchStartX + swThreshold) < touchMoveX) {
		// from LEFT to RIGHT
		img.style.opacity = 0.3;
		moveHrefID('prev');
	    }
	}
    }, false);
}, false);
EOF
}
[ "$usejs" ] && mkjs

##mkorder function
mk_order () {
    perl=`which perl`
    if [ -x /usr/lib/sendmail ]; then
	sendmail=/usr/lib/sendmail
    elif [ -x /usr/sbin/sendmail ]; then
	sendmail=/usr/sbin/sendmail
    else
	sendmail=sendmail
    fi
    tojis=`which nkf`
    while [ "$toaddress" = "" ]; do
	printf "注文を受ける人のemailアドレス: "
	read toaddress
    done
    while [ "$maintainer" = "" ]; do
	printf "このページの管理者(多分あなた)のemailアドレス: "
	read maintainer
    done
    cat>order.pl<<EOF
#!$perl

@list='';
\$sendmail='$sendmail';
\$replyto='$toaddress';
\$mailto='';
\$maintainer='yuuji@itc.keio.ac.jp';
\$tojis='$tojis';

while (\$ARGV[0] =~ /^-/) {
    if (\$ARGV[0] =~ /^-email/) {
	\$mailto = \$ARGV[1];
    } elsif (\$ARGV[1] =~ /on/i) {
	push(@list, \$ARGV[0]);
    }
    shift; shift;
}

print "<html><head><title>Accepted</title><head><body>";

if (\$mailto) {
    open(MAIL, "|\$tojis | sendmail \$mailto");
    print MAIL "To: \$mailto
From: Photo Ordering System <\$maintainer>
Subject: Confirmation of your order
Reply-to: \$replyto

以下の写真注文を受理しました。以下のリストであっているかどうか確認し、
これで良ければ、このメイル全体を引用して \$replyto にご返送ください。
";

    print MAIL join("\n", @list);
    close(MAIL);
    print "注文リストを送信しますので合っているかどうか確認してください。";
    
} else {
    print "メイルアドレスは必ず入れてください。";
}
print "</body>\n</html>";
EOF
    chmod +x order.pl
}

if [ "$noindex" -eq 0 ]; then
	if [ "$TABLE" ]; then
	  echo "</table>"				>&$iout
	  if [ "$formhead" ]; then
	    $tojis<<EOF>&$iout
<input type=submit value="注文">
$formtail
EOF
	  mk_order
	  fi
	fi
	if [ "$init" -eq 2 ]; then
	  echo "$tailer"				>&$iout
	elif [ "$init" -ne 0 ]; then
	  echo ""					>&$iout
	  echo "$eofm1"					>&$iout
	  echo "</p></div>"				>&$iout
	  echo "</body>"				>&$iout
	  echo "</html> $eofm2"				>&$iout
	fi
fi