#!/bin/bash


#A script run from a terminal using ImageMagick options (and some specialised scripts downloaded from
#http://imXw.fmwconcepts.com/imagemagick/  enrich, aspectcrop,  enhancelab) to process (normalize; sharpen; resize to display;
#enrich; enhance) and show a slideshow of an image placed in /tmp without changing the original image.
#Depends on jhead to interpret exif data in the image (creation time, camera).
#Uses the feh image program to show the slideshow. feh provides various benefits
#such as some keyboard interation / to fill window; d to show the name 
#m to show an onscreen menu; numeric + -  or up and down arrows to zoom or not; o to hide mousepointer
#This script uses IM internal format for image processing up to the point of display.
#The number of images to be displayed and a restart point #can also be specified if required.
#Needs imagemagick,enrich,aspectcrop,enhancelab,jhead,feh

#Typical use: ./showslides -h   : help message
#             ./showslides -WEL beach     : shows all images with beach in their name

cycletime="10"
picktype="sort"  #"shuf" #default is to view in file order but option to use shuffle if desired
imcount=1
ccount=0
labelcolour="pink"
original='y'
warg=6800
startofcycle="0"
aspectratio="16:9"
offscreen=''
restart=0
numberimages=1000000
cval_enhance=0
folderdepth='1'
myfont=""
label=''
time=''
date=''
cam='y'
seqno=''
procops=''
labelx='64' #where to place label
labely='120'
labelgrav='southwest'
 
#================================================
helpmsg() {
#prints after a bit of tidying the option list as delineated by #NTH and #STH
echo "Options for ${0##*/} :"
#NTH  can be required for some reason ?
t=$(sed  '/NTH/,/STH/!d' "$0" | sed '/^#N/d; /^#S/d; /^sed/d')  #last section suppresses showing command and markers
t=$( echo "$t" | sed -e 's/ +//g; s/shift\; if \[ \-n \"\$1\" \]\; then//g; s/;*//g; s/)//g;')
t=$(echo "$t" | sed '/-/!d; /|/!d;  /--/!d; s/\#//;s/shift//;')
echo "$t"
}
#================================================
getvars() {
#based on https://blog.onetechnical.com/2012/07/16/bash-getopt-versus-getopts/
# Execute getopt

ARGS=$(getopt -o "a:bBCc:dDeEfhklLNn:OpWxsSotu:TWr:qy:z" -l "aspect:,copy,beforeafter,blurx,helpmsg,contrast,\
date,default,enrich,enhancex,f1,f2,f3,f4,f5,favorites,help,label,longlabel, \
time,labelcolour=:,original,sharpx, \
warmerx,restartfrom=:,seqno,cycletime=:,numberofimages=:,showoptions,xscreenoff,userops:,zoom" \
 -n "getopt.sh" -- "$@");

#echo "AFTER  GETOPT: $@";

#Bad arguments
[ $? != 0 ] && exit 1
#[ $# -eq 0 ] && helpmsg; exit 0

eval set -- "$ARGS";
#echo "AFTER SET -- \$ARGS: $@";

#store arguments in ops string
ops=''
ops1=''
ops2=''
ops3=''
ops4=''

while true; do
  case "$1" in
#NTH
    -B|--beforeafter) shift;                         #showing before after
		beforeafter='y'
		echo "Showing before after"
	;;
    -a|--aspect=) shift;                             #eg -a 16:9
		testfornumber $1
		aspectratio="$1"
        echo "Aspectratio : $1";
        shift
    ;;
    -b|--blurx) shift;                               #eg -bbb sets blur parameter to 3x0.03 = 0.09
		barg="$[barg+3]"
		blur='y';
		#allow for increasing blur effect by 0.03 by including multiple blurs
		if [[ $barg -le 9 ]]; then ops1=" -blur 0x0.0$barg";  else ops1=" -blur 0x0.$barg";fi
		echo "Adding blur of 0x$barg"
		m1='b'"$barg"
	;;
    -C|--contrast) shift;                            #increases contrast using -sigmoidal-contrast 3x50%
		ops2=$" -sigmoidal-contrast 3x50%"
		echo "sigmoidal-contrast 3x50% "
		m2='c'
    ;;
    -c|--cycletime=) shift;                          #eg -c 25  sets cycletime to 25sec
		testfornumber $1
		cycletime="$[$1+2]"
        echo  "Cycletime : $cycletime sec";
        shift;
    ;;
    -D|--database_images) shift;
        imsdb='y'
        echo "Rebuilding image database"
    ;;    
    -d|--date) shift;
        date='y'
        echo "Include date"
    ;;
    -E|--enhancex) shift;                            #Freds enhancelab eg -EEEE sets c param to 4x5 = 20
		cval_enhance=$[cval_enhance+5]
		enhance='y'
		echo "Using Freds enhancelab  c is $cval_enhance"
	;;
    -e|--enrich) shift;                              #use Freds enrich
		enrich='y'
		echo "Using Fred's enrich"
	;;
    -f|--favorites) shift;                           #as shown
		#normalize='y'
		enrich='n'
		enhance='y'
		cval_enhance=10
		#warmtemp="5800"
		label='y'
		time='y'
		date='y'
		seqno='y'
		procops='y'
	  	echo "Using favourites"
	;;
    -h|--helpmsg) shift;
  	    helpmsg
  	    exit 0
    ;;
    -k|--copy) shift;                                #save a copy with selected options added to each name
		copy='y'
		echo "Making a copy  with option shown in title"
	    mkdir ./beforeafters
	;;
    -L|--longlabel) shift;                           #show everything in label
        label='y'
        seqno='y'
		date='y'
		time='y'
		cam='y'
		procops='y'
        echo "Show everything in label"
    ;;
    -l) shift;                                       #no date and time information
		label='y'
		echo "Applying short $labelcolour label"
	;;
    -n|--numberofimages=) shift;                     #eg -n 25
    	numberimages=$1
		shift
        ;;
    -N|--normalize) shift;
		normalize='y'
		echo "Normalizing"
		ops4=" -normalize"
		m4='N'
	;;
    -O|--original) shift;                            #original view shows all of image : default
	    echo "$1 original view"
		original='y'
	;;
    -p|--showoptions) shift;                         #options used are added to title
		procops='y'
		echo "Include process options in label"
	;;
    -q|--seqno) shift;                               #add sequence data to label
		seqno='y'
        echo "Sequence data in label"
	;;
    -r|--restartfrom=) shift;                        #eg -r 10 will (re)start from image no 10
		testfornumber "$1"
		restart=$1
		echo "Restart at : $restart";
		restart=$[restart-1] #account for zero shift
        shift
    ;;
    -s|--sharpx) shift;                              #sharpen image eg: -ss sets unsharp arg to 0.10
       	sarg=$[sarg+5]      #-unsharp 0x6+0.5+0 according to imagemagick wp
    	if [[ $sarg -le 9 ]]; then
    	    ops3=" -unsharp 0x1.0+1.0+0.0$sarg";  else ops3=" -unsharp 0x1.0+1.0+0.$sarg";fi
            echo  "Sharpen $ops3";
            m3='s'$sarg
    ;;
    -S|--shuffle) shift;                             #view images in random order
    	picktype="shuf"
    	echo  "Shuffle";
    ;;
    -t|--time) shift;                                #include imY:MM in label
        time='y'
        label='y'
        echo "Include imY:MM in label"
    ;;
    -T|--titlecase) shift;                           #don't use title case
    	nousetc='y'
    	echo "Not using titlecase"
    ;;
    -u|--userops=) shift;                            #enter one or more of the convert ops eg -equalize. 
		#option should include -, as in -contrast, pr +, as in +contrast
		# and any required args need another -u or --user  eg -u-shade -u45x0"
		userops="$userops"" ""$1"
		echo "userops $1"
		m5="$m5"" ""$1"
		shift
	;;
    -W|--warmerx) shift;                             #decrease colour temp by -1000 each time
        warg=$[warg-1000]
	    warmer='y'
	;;
    -x|--xscreenoff) shift;                          #no display
		offscreen="1"
        echo  "No display";
    ;;
    -y|--labelcolour=) shift;
		labelcolour=$1;label="y";
		echo "Applying $1 label"
		shift
	;;
    -z|--zoom) shift;                                #this view clips image to fill screen
	    echo "Zoom to fill screen"
	    original=''
	;;
    --) shift;
        break;
  	;;
  #  -*) echo "Invalid Optionss $1.  Try $0 --help to see available options."
  #     exit 0
 #	;;
#STH
esac
done
glob="$@"
#sleep 5  #give time to read messages in terminal so far
}

#================================================
testfornumber() {
re='^[0-9:\-\+\.]+$'
if ! [[ $1 =~ $re ]] ; then
   echo "Check args : $1 is not a number" >&2; exit 1;
fi
}

#================================================
titlecase() {
#NB note -E sed option
#input can be a range of characters in a string separated by _,;:(){}-; multiple spaces and conjoined letters and text,
#if text is continous use extractwords -see below
Title=$(echo "$1" | sed -E  "s/([0-9])([a-zA-Z])/\1 \2/g; s/[_,;:(){}-]/ /g; s/  +/ /g; s/ - /-/g;  s/(^| )([a-z])/ \u\2/g")
Title=$(echo "$Title" | sed -E "s/ And / and /g; s/ In / in /g; s/ To / to /g; s/ At / at /g; s/Im/ /g; s/ Th /th /g;  s/ Th /th /g; s/ Nd /nd /g; " ) # s/[A-Z] //g" )  #last term eliminates a,b,c subscripts of time differentiation
#Title=$(extractwords.py -t "$1" -T )
#The previous line does this better and is a python program that separates words from a contiguous text string
#(uses a 125,000 plus word dictionary : extractwords-by-frequency.txt)
}
#=========================================
read_timestamp_camera()
{
#extract date from file exif using jhead or file name assuming in format 20160812-123456-xxxx.jpg
#or at least a year eg 1945ca
#a1=$(jhead -v "$1" | grep -i date | gawk -F':' '{print $2$3$4$5}' | tail -1 ) #$6 would give seconds
#echo $a1

if [[ $cam ]]; then  #get camera make-model
	a1=$(jhead "$1" | grep -i model )
	cmake="${a1##*:}"
	echo $cmake
fi

if [[ $date ]]; then
    image="${1##*/}"
    ts=''
	a1=$(jhead  "$image"| grep Date | sed 's/:/-/g' | sed 's/-/:/g4')  #get any date info
	#output of grep Date is     Date/Time    : 2018:06:28 15:07:25
	# sed expressions replace all : with - and then all - with : g4 after 4th
	#--> Date/Time     : 2008-10-23 13:44:51  -for date to be able to interpret properly
	a1="${a1:14:20}"  #extract only the date data 
	
    if [[ "$a1" ]]; then 
        ts=$(date +%a' '%d' '%b' '%Y' ' --date="$a1")
	    if [[ $time ]]; then 
	        ts=$ts$(date +' '%H':'%M' ' --date="$a1")
	        echo -e "Exif date $ts"
	    fi
	    return
	else
        echo "No exif time data. Trying file name."
        mo='';dy=''
        a2=${image//[^0-9]/}  #extract only digits
		echo $a2
        #assign to various date components      
		yr=${a2:0:4}
		mo=${a2:4:2}
		if [[ $mo -lt 1 ]] || [[ $mo -gt 12 ]]; then mo='';fi
		dy=${a2:6:2}
		if [[ $dy -lt 0 ]] || [[ $dy -gt 31 ]]; then dy='';fi
		# bash treats leading 0 as octal indicator : eliminate
		hr=${a2:8:2}; hr=${hr#0}
		if [[ $hr -lt 0 ]] || [[ $hr -gt 23 ]]; then hr='';fi
		mn=${a2:10:2}; mn=${mn#0}
		if [[ $mn -lt 0 ]] || [[ $mn -gt 59 ]]; then mn='';fi
		sc=${a2:12:2}; sc=${sc#0}
		if [[ $sc -lt 0 ]] || [[ $sc -gt 31 ]]; then sc='';fi
  
		a1="$yr-$mo-$dy $hr:$mn:$sc"
        a1=$(echo $a1 | sed -e 's/[^0-9]\+$//' | sed -e 's/::/:/')  #eliminate non-numerics at end of a1 & :: 
        echo -e "Header data $a1  length ${#a1}"
        
    	if [[ ${#a1} -ge 9 ]]; then   #eg 2018-10-30 12:14:16
    	 	ts=$(date +%a' '%d' '%b' '%Y' ' --date="$a1")
	        if [[ $time ]]; then 
	            ts=$ts$(date +' '%H':'%M' ' --date="$a1")
	            ts=$(echo $ts | sed 's/00:00//')
	        fi
			return
	    fi    
	    if [[ ${#a1} -gt 4 ]]; then #eg 2008-07 but add a dummy day to use date fn
	        a1=$a1"-01"
	   		ts=$(date +%b' '%Y' ' --date="$a1")
    	else
            ts=$yr
        fi  
    fi 
    echo "Time stamp   $ts"      
fi	

}
#=========================================
get_name() {
#get file name without any extension #an=$(echo "${PWD##*/}")
    name="${1##*/}"   #get short path file name ${1##*/}
    cn="${name%.*}"  #remove last extension
	cn=$(echo $cn | sed -e 's/-[A-Za-z]$//')  #remove any SINGLE letters following a - at end of title 
	# eliminating _,;:(){}-] ; capitalizing first words; eliminating more than one space
	cleanname=$(echo "$cn" | sed -e "s/[_,;:(){}-]/ /g; s/^[a-z]/\U&/;s/ \+/ /g;s/ - /-/g; s/[0-9]//g")
	if [[ $nousetc ]]; 
	then
	    echo "Not using titlecase"
	else   
		titlecase "$cleanname"
		cleanname="$Title"
	fi
    ftype="${name##*.}"  #filetype
}
#=========================================
check_image() {
    #checks whether we are dealing with a valid image file using imagemagick identify command
    identify -quiet -ping "$1" > /dev/null  #suppress ordinary output
    if [[ $? -ne "0" ]]; then echo -e "$1 Not a valid image file. Ignored.\n"; return 1;
    else return 0; #returns 0 if passed
    fi
}
#=========================================
find-images-in-directory() {
#find list all valid images in directory and subdirectories
#find . -depth -type f -iname "*.png" -o -iname "*.jpg" \
# -o -iname "*.jpeg" -o -iname "*.bmp " > _0-ims-found.txt
find . -depth -type f  -iregex ".*\.\(png\|jpg\|jpeg\|bmp\|.gif\|tiff\)" > _0-ims-found.txt
allimcount=$(wc -l < _0-ims-found.txt)
echo $allimcount
[ $allimcount -gt 0 ] && echo -e "\nRebuilt images in directory file. Total number is $allimcount\n"
}
#=========================================
selected-images() {
#start by making a list selected from _0-ims-found.txt in _0-sel-ims.txt
echo $0
echo =====================================
echo
echo -e "Search term .. length ${#glob} : ${glob:0:100} "
if [ ${#glob} -gt 50 ]  #probably shell expansion involving *
then
    glob=''
    echo -e "\nDon't use * unless with text that will pick one file only.\nDon't normally need it.\n"
fi
#[ -z "$glob" ] && echo "Showing all"
> _0-sel-ims.txt
# write selected filenames
$picktype _0-ims-found.txt | grep "$glob" >> _0-sel-ims.txt
imcount=$(wc -l < _0-sel-ims.txt)
[ $imcount != 0 ] && echo "Number images found $imcount"
}
#===========================================
run-images() {
#make run selection
imcount=$(wc -l < _0-sel-ims.txt)
> _0-run-ims.txt
tail -$[imcount-restart] _0-sel-ims.txt >> _0-run-ims.txt
if [[ $imcount -lt $numberimages ]]; then numberimages=$imcount;fi
echo -e "Showing $numberimages images out of $imcount starting at $[restart+1]\n"
}
#=========================================
add-label() {
read_timestamp_camera $image
get_name $image  #tidies up filename for use in label
fillcolor=$labelcolour
pointsz=$[imY/45]  #use a smaller denominator to get a larger label 
if [[ $pointsz -lt 12 ]]; then pointsz=12;fi
cropsz=$pointsz   #adjust these if necessary to fit display
if [[ $procops ]]; then processoptions="$poptions   ";fi
ccount=$[nn+restart]
echo -e "Full Label: $cleanname $ts $processoptions   $ccount/$imcount    $cmake" 
if [[ $seqno ]]; then lab='\n'"$cleanname $ts        $ccount/$imcount    $cmake    $processoptions"
else lab='\n'"$cleanname $ts $processoptions" 
fi
echo -e "$lab"
#crop takes an bit from top to maintain aspect and fill screen wo borders
convert /tmp/tmp '(' -background black -fill $fillcolor -pointsize $pointsz  \
label:"$lab" -gravity Center ')' -gravity South -crop +0-$cropsz +repage -append  /tmp/tmp
}
#=========================================
mainloop() {
# remove temp images and _0-  text files if unprogrammed/normal exit (inspired by Fred but in bash)
trap "rm -fv /tmp/tmp* /tmp/namelist _0-*; echo Finished. Bye! ;pkill feh; exit 0" 0
trap "rm -fv /tmp/tmp* /tmp/namelist & echo ' '"Interrupted".;pkill feh; exit 1" 1 2 3 15  #see trap -l
nn=0 
#process each image one by one
cat _0-run-ims.txt | while read image
do
   	nn=$[nn+1]
    if [[ $nn -gt $numberimages ]]; then exit 0; fi

    echo -e "\n===============\nCurrent file is : $image   { no: $[nn+restart] }"
	#check_image "$image" > /dev/null #a valid image?
	if [[ $? -eq 0 ]]; then echo OK; else echo NOT OK; continue;fi

    poptions=""
    #=================================================================================
    poptions="$m0$m1$m2$m3$m4$m5$poptions"
    #echo "Options : $poptions"
    echo -e "convert -auto-orient $ops1 $ops2 $ops3 $ops4 $ops5 $userops $image /tmp/tmp" 
	#sharpen blur brightness-contrast userops
    convert -auto-orient $ops1 $ops2 $ops3 $ops4 $ops5 $userops "$image" /tmp/tmp
    if [[ $? -eq 1 ]]; then echo -e "Error in convert"; exit 1; fi # exit on error
    #determine image dimensions and aspect ratio copying from fred's aspectcrop
    imY=$(identify -ping -format '%h'  /tmp/tmp)  #needed for label font size
    imX=$(identify -ping -format '%w'  /tmp/tmp)   #and aspect ratio modification if appropriate
	ratio=`convert xc: -format "%[fx:$imX/$imY]" info:`
	ar=${ratio:0:4}  #convert to 1.xx format
	echo "width=$imX; height=$imY; ratio=$ar"

    if [[ $warmer ]]
    then
        warmtemp=$warg
    	~/bashstuff/colortemp-im-fred -t $warmtemp /tmp/tmp /tmp/tmp
    	poptions=$poptions"W$[warmtemp/1000]"
	fi

	#-w 80 -g 1.3 -c 30  for enhancelab-im-fred: start with 5  -c 25 only seems about right
	if [[ $enhance ]]; then
	    ~/bashstuff/enhancelab-im-fred  -c $cval_enhance /tmp/tmp /tmp/tmp
		poptions=$poptions"E$cval_enhance"
	fi

	if [[ $enrich ]]; then
	 	~/bashstuff/enrich-im-fred.sh /tmp/tmp /tmp/tmp
	 	poptions=$poptions"e"
	fi
	
	if [[ -n $cyc1 ]]; then echo "Options applied ; "$poptions; fi;

	if [[ $beforeafter ]]; then
	    convert "$image" /tmp/tmp +append /tmp/tmp 
    fi
		(
			if [[ $original ]]; then 
				asp=''; 
			else # widen aspect ratios less than 14:9 to 14:9 
				#neimXidth=$(python2 -c "print($imX*16/9)")
				#echo $neimXidth
				#convert /tmp/tmp -resize $neimXidth! /tmp/tmp
				if [[ $ratio < 1.50 ]]; then 
					asp="-a 14:9"; #asp="-a $aspectratio";fi;
					#echo "aspect set to : 13:9"
					#asp=''
					#neimXidth=$(python -c "print($imX*16/9)")
					#echo $neimXidth
					#convert /tmp/tmp -resize $neimXidthx$imY /tmp/tmp
					else 
					asp="-a $aspectratio"	
				fi
			fi
			#if [[ $ratio > 1.00 ]]; then  #gravity north crops bottom of non:16:9 images
				~/bashstuff/aspectcrop-im-fred $asp -g north /tmp/tmp /tmp/tmp 
			#fi		
			if [[ $label ]]; then add-label; fi
			#provide an outline frame
    		convert /tmp/tmp -mattecolor tan4 -frame 6x6 -raise 3 /tmp/tmp
			convert /tmp/tmp /tmp/tmp.jpg
			if [[ $copy ]]; then #name to use
				copyname=$(echo "$cn-$processoptions.jpg" | sed "s/ //g")
				cp /tmp/tmp.jpg "./beforeafters/$copyname"
				cp $image "./beforeafters/$name"
			fi
 	        if [[ ! $offscreen ]]; then /usr/bin/feh -F --auto-zoom /tmp/tmp.jpg; fi
		)  &  # & is necessary
        sleep $cycletime
		((  nn > 1 )) && pkill --oldest feh
		continue  #stop final image by ^-Q if necessary
done
}
#==============================================================================
#main processing loop
#run the script

#if [[ ! -f _0-ims-found.txt ]]; then find-images-in-directory;fi
getvars $@
find-images-in-directory
selected-images
run-images

mainloop $ims

exit 0
