#!/bin/ksh
# @(#) ppmbrowse.ksh 1.0 94/04/02
# 94/04/02 john h. dubois iii (john@armory.com)

alias istrue="test 0 -ne"
alias isfalse="test 0 -eq"

name=${0##*/}
Usage="Usage: $name [-hmxgpP] [-c columns] [-b background-color]
    [-B border-width] [-S separation] [-V vertical-separation]
    [-H horizontal-separation] [-i image-map-format-string] [-f image-map-file]
    [-t text-color] [-q quantized-colors] [-s size] ppm-image [ppm-image ...]"

Background=blue
Text=white
typeset -i Vertical=2 Horizontal=5 Colors=0 Columns=6 Size=100 Debug=0
typeset -i Border=5 Preserve=0 MakeMap=0

typeset -i InfX InfY
function pnminfo {
    typeset j1 j2 j3 j4
    [ $# -gt 0 ] && pnmfile "$1" | read j1 type j2 InfX j3 InfY j4 ||
     pnmfile | read j1 type j2 InfX j3 InfY
}

# Usage: MakeRow file ....
# Uses globals: HSepFile (horizontal separator), Debug, Row, Tmp, Horizontal,
# MapStr
# Adds new row file to RowFiles[].
# Runs PrintMap if making image map.
function MakeRow {
    typeset Files file RowTmp

    # If any horizontal separtion, add it in
    if istrue Horizontal; then
	Files=$1
	shift
	for file; do
	    Files="$Files $HSepFile $file"
	done
    else
	Files=$*
    fi
    let Row+=1
    RowTmp=$Tmp.r.$Row.$$
    RowFiles[Row]=$RowTmp
    istrue Debug && print -u2 "Row: $Row.  RowFile: $RowTmp.  Files: $Files."
    pnmcat -lr $Files > $RowTmp
    istrue MakeMap && PrintMap $Row
}

# Usage: PrintMap row
# Write image map file to fd 3
# Globals: 
# FileNames[]	Base names of files in this row
# MapStr	Proto-URL
# Vertical	Vertical separation between images
# Horizontal	Horizonal separation between images
# Size		Width of map area
# ThumbYDim	Height of map area
# Border	Width of border
# Columns	Number of columns in widest row
function PrintMap {
    typeset -i Row=$1 Left=Border Right Bottom Top XShift ColNum=0 NFiles
    typeset file MapOut
    
    NFiles=${#FileNames[*]}
    if [ NFiles -lt Columns ]; then
	let Left+="(Columns-NFiles)*(Size+Horizontal)/2"
    fi
    Top="(Row-1)*(Vertical+ThumbYDim)+Border"
    Bottom=Top+ThumbYDim-1
    for file in "${FileNames[@]}"; do
	Right=Left+Size-1
	Replace %s "$file" "$MapStr"
	MapOut="rect $Replace_return $Left,$Top $Right,$Bottom"
	istrue Debug && print -u2 "Image map string: $MapOut"
	print "$MapOut" >&3
	Left=Right+Horizontal+1
    done
    unset FileNames[*]
}

# Usage: Replace <repl> <with> <string>
# Replaces the first instance of <repl> in <with> with <string> and assigns the
# result to Replace_return.
function Replace {
    Replace_return="${3%%$1*}$2${3#*$1}"
}

# Usage: MakeBr file ....
# Uses globals: VSepFile (vertical separator), Debug, Vertical
function MakeBr {
    typeset Files file

    # If any Vertical separtion, add it in
    if istrue Vertical; then
	Files=$1
	shift
	for file; do
	    Files="$Files $VSepFile $file"
	done
    else
	Files=$*
    fi
    istrue Debug && print -u2 "Files: $Files."
    pnmcat -tb $Files
}

set -e	# Exit if non-num parm assigned to integer var
while getopts :hc:b:t:S:V:H:q:s:xPf:i:mgp opt; do
    case $opt in
    h)
	echo \
"$name: make an image browser from a group of image files.
$name makes a single image containing thumbnail versions of each
named image file, with a label under each.
$Usage
Options:
-h: Print this help.
-x: Turn on debugging.
-P: Preserve (do not remove) tmp files.
-c: Set the number of images in each row.  The default is $Columns.
-b: Set the background color.  The default is $Background.
-B: Set the border width.  The default is $Border pixels.
-t: Set the text color.  The default is $Text.
-V: Set the separation between rows.  The default is $Vertical pixels.
-H: Set the separation between columns.  The default is $Horizontal pixels.
-S: Set both the horizontal and vertical separation.
-q: Set the number of colors the final image is quantized to.
    The default is no quantization.
-s: Set the size of the thumbnail images.  The default is $Size pixels.
    If the largest dimension of the image is smaller than the given size,
    it is not scaled.  If it is larger, the image is scaled so that its
    largest dimension is equal to the given size.
-i: Create a www-style image map for the browser.  The string given with -i
    should be a URL, with a %s where the base name of the file should
    be substituted in.  A default line with \"nosel.html\" substituted for %s
    will be put at the top.  Example: http://www.armory.com/~spcecdt/%s.jpg
    If -f is given and -i is not, the default of just %s by itself is used.
-f: Specify an output file for the image map.  If -i is given and -f is not,
    it will be written to the file browser.map.
-g: Produce output in GIF format.
-p: Produce output in ppm format (default).
-m: Set the defaults for certain options to those appropriate for an image map.
    Quantization is set to 240 colors, an image map is produced with defaults
    as described for -i and -f, and the output is in GIF format.
    Options given later on the command line can override these."

	exit 0
	;;

    c)  Columns=OPTARG;;
    b)  Background=$OPTARG;;
    t)  Text=$OPTARG;;
    V)  Vertical=OPTARG;;
    H)  Horizontal=OPTARG;;
    S)  Vertical=OPTARG Horizontal=OPTARG;;
    q)  Colors=OPTARG;;
    s)  Size=OPTARG;;
    x)  Debug=1;;
    P)  Preserve=1;;
    i)  MapStr=$OPTARG MakeMap=1;;
    f)  MapFile=$OPTARG MakeMap=1;;
    g)  OutputConvert=ppmtogif;;
    p)  unset OutputConvert;;
    m)  Colors=240 MakeMap=1 OutputConvert=ppmtogif;;
    +?)
	print -u2 "$name: options should not be preceded by a '+'."
	exit 1
	;;
    ?) 
	print -u2 "$name: $OPTARG: bad option.  Use -h for help."
	exit 1
	;;
    esac
done
 
set +e

# remove args that were options
let OPTIND=OPTIND-1
shift $OPTIND

if [ $# -lt 1 ]; then
    print -u2 "$Usage\nUse -h for help."
    exit
fi

typeset -i NumFiles=$# Rows Size XDim YDim LabelHeight ThumbXOff LabelXOff
typeset -i LabelX LabelY ThumbYOff LabelYOff ThumbYDim Column=0 Row=0

Rows="(NumFiles+Columns-1)/Columns"
XDim="Border*2+(Columns-1)*Vertical+Columns*Size"
YDim="Border*2+(Rows-1)*Horizontal+Rows*Size"

# Quit if anything fails
set -e

# Labels come out different heights, but this is good enough
pbmtext XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  | pnminfo
LabelHeight=InfY
FontWidth=InfX/40
typeset -L$((Size/FontWidth-2)) Label

istrue Debug && print -u2 \
"NumFiles=$NumFiles Rows=$Rows XDim=$XDim YDim=$YDim LabelHeight=$LabelHeight"

Tmp=${TMP:-/tmp}/ppb
ThumbBack=$Tmp.tb.$$
ThumbTmp=$Tmp.t.$$
LTmp=$Tmp.l.$$
HSepFile=$Tmp.hs.$$
VSepFile=$Tmp.vs.$$
isfalse Preserve && 
trap "rm -f $ThumbBack $ThumpTmp $ThumpLTmp $LTmp $Tmp.t.+([0-9]).$$ "\
"$VSepFile $HSepFile $Tmp.r.+([0-9]).$$ $ThumbTmp; exit" EXIT 1 2 3 15
    

# Create background for image part of one element
ThumbYDim=Size+LabelHeight
ppmmake $Background $Size $ThumbYDim > $ThumbBack

if istrue Debug; then
    pnminfo $ThumbBack
    print -u2 "Made $InfX x $InfY background."
fi

# Create horizontal separator if it will be needed
istrue Horizontal && ppmmake $Background $Horizontal $ThumbYDim > $HSepFile

# Create vertical separator if it will be needed
if istrue Vertical; then
    typeset -i TotWidth="Size*Columns+Horizontal*(Columns-1)"

    istrue Debug && print -u2 "Making $TotWidth x $Vertical vertical separator"
    ppmmake $Background $TotWidth $Vertical > $VSepFile
fi

if istrue MakeMap; then
    [ -z "$MapStr" ] && MapStr=%s
    [ -z "$MapFile" ] && MapFile=browser.map
    # Make fd 3 be the map output file
    exec 3>"$MapFile"
    Replace %s "$file" nosel.html
    print -r "default $Replace_return" >&3
fi

for file; do
    # Make label file
    Label=${file%.*}
    pbmtext $Label | pgmtoppm $Text-$Background > $LTmp
    pnminfo $LTmp
    LabelX=InfX
    LabelY=InfY
    # Make thumbnail file
    pnmscale -xysize $Size $Size $file > $ThumbTmp
    pnminfo $ThumbTmp
    ThumbXOff="(Size-InfX)/2"
    ThumbYOff=Size-InfY
    LabelXOff="(Size-LabelX)/2"
    LabelYOff="ThumbYDim-LabelY"
    istrue Debug && print -u2 \
"Thumbnail is $InfX x $InfY.  Label is $LabelX x $LabelY.
Pasting thumbnail in at x offset $ThumbXOff, y offset $ThumbYOff.
Pasting label in at x offset $LabelXOff, y offset $LabelYOff."
    let Column+=1
    ThumbLTmp=$Tmp.t.$Column.$$
    ThumbFiles[Column]=$ThumbLTmp
    FileNames[Column]=${file%.*}	# For the image map
    pnmpaste -replace $ThumbTmp $ThumbXOff $ThumbYOff $ThumbBack |
    pnmpaste -replace $LTmp $LabelXOff $LabelYOff > $ThumbLTmp
    if [ Column -eq Columns ]; then
	MakeRow "${ThumbFiles[@]}"
	unset ThumbFiles[*]
	Column=0
    fi
done
istrue Column && MakeRow "${ThumbFiles[@]}"

Pipeline="MakeBr ${RowFiles[*]}"
istrue Colors && Pipeline="$Pipeline | ppmquant -fs $Colors"
istrue Border && Pipeline="$Pipeline | pnmmargin -color $Background $Border"
[ -n "$OutputConvert" ] && Pipeline="$Pipeline | $OutputConvert"

eval $Pipeline
