#!/bin/bash
#
# Developed by Fred Weinhaus 7/5/2010 .......... 1/12/2017
#
# ------------------------------------------------------------------------------
# 
# Licensing:
# 
# Copyright © Fred Weinhaus
# 
# My scripts are available free of charge for non-commercial use, ONLY.
# 
# For use of my scripts in commercial (for-profit) environments or 
# non-free applications, please contact me (Fred Weinhaus) for 
# licensing arrangements. My email address is fmw at alink dot net.
# 
# If you: 1) redistribute, 2) incorporate any of these scripts into other 
# free applications or 3) reprogram them in another scripting language, 
# then you must contact me for permission, especially if the result might 
# be used in a commercial or for-profit environment.
# 
# My scripts are also subject, in a subordinate manner, to the ImageMagick 
# license, which can be found at: http://www.imagemagick.org/script/license.php
# 
# ------------------------------------------------------------------------------
# 
####
#
# USAGE: enrich [-r radii] [-t transparency] [-w weights] [-b bias] [-c compose] infile outfile
# USAGE: enrich [-help or -h]
#
# OPTIONS:
#
# -r      radii              two radii for sharpening; radii=large,small; 
#                            floats>0; default="60,3"
# -t      transparency       two transparency percentages corresponding to the 
#                            radii; 0<float<100; default="40,50"
# -w      weights            weights for generating high pass filter from 
#                            image minus the low pass filtered (blurred) image;
#                            weights=imageval,lowpassval; floats>0;
#                            default="1,1"
# -b      bias               bias value for the two high pass filtered images; 
#                            0<float<100; default=50
# -c      compose            compose methods corresponding to radii; 
#                            default=hardlight,overlay
#
###
#
# NAME: ENRICH 
# 
# PURPOSE: To enhance an image by high pass filtering and composition.
# 
# DESCRIPTION: ENRICH enhances an image by high pass filtering and composition. 
# The high pass filter is generated by subtracting a low pass filtered 
# (blurred) version of the image from the image at two different filter sizes 
# and then compositing them with the image with specified transparency.
# 
# 
# OPTIONS: 
# 
# -r radii ... RADII=LARGE,SMALL. Two required radii for the size of the high 
# pass filters. Values are floats greater than 0. The default="60,3".
#
# -t transparency ... TRANSPARENCY values for two high pass filtered images. 
# Values are floats in the exclusive range of 0 to 100. The default="40,50".
# 
# -w weights ... WEIGHTS for generating the high pass filtered images by  
# subtracting the low pass filtered images from the image. The first value is 
# for the image and the second value is for the low pass filtered image. The 
# same values will be used for both high pass filtered images. Values are 
# floats greater than 0. The default="1,1".
# 
# -b bias ... BIAS to be used when generating the high pass filtered images. 
# The same value will be used for both high pass filtered images. Values are 
# floats in the exclusive range 0 to 100. The default=50.
# 
# -c compose ... COMPOSE methods to use with each high pass filtered image. 
# Any valid IM compose method without arguments is permitted. The 
# default="hardlight,overlay"
# 
# Concept provided by Philip Morgan
# 
# CAVEAT: No guarantee that this script will work on all platforms, 
# nor that trapping of inconsistent parameters is complete and 
# foolproof. Use At Your Own Risk. 
# 
######
#

# set default values
radii="60,3"					# radii (large,small)
alphas="40,50"					# transparencies
weights="1,1"					# image - blurredimage weights
bias=50							# filter bias
compose="hardlight,overlay"		# compose methods


# set directory for temporary files
dir="."    # suggestions are dir="." or dir="/tmp"

# set up functions to report Usage and Usage with Description
PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGDIR=`dirname $PROGNAME`            # extract directory of program
PROGNAME=`basename $PROGNAME`          # base name of program
usage1() 
	{
	echo >&2 ""
	echo >&2 "$PROGNAME:" "$@"
	sed >&2 -e '1,/^####/d;  /^###/g;  /^#/!q;  s/^#//;  s/^ //;  4,$p' "$PROGDIR/$PROGNAME"
	}
usage2() 
	{
	echo >&2 ""
	echo >&2 "$PROGNAME:" "$@"
	sed >&2 -e '1,/^####/d;  /^######/g;  /^#/!q;  s/^#*//;  s/^ //;  4,$p' "$PROGDIR/$PROGNAME"
	}


# function to report error messages
errMsg()
	{
	echo ""
	echo $1
	echo ""
	usage1
	exit 1
	}


# function to test for minus at start of value of second part of option 1 or 2
checkMinus()
	{
	test=`echo "$1" | grep -c '^-.*$'`   # returns 1 if match; 0 otherwise
    [ $test -eq 1 ] && errMsg "$errorMsg"
	}

# test for correct number of arguments and get values
if [ $# -eq 0 ]
	then
	# help information
   echo ""
   usage2
   exit 0
elif [ $# -gt 12 ]
	then
	errMsg "--- TOO MANY ARGUMENTS WERE PROVIDED ---"
else
	while [ $# -gt 0 ]
		do
			# get parameter values
			case "$1" in
		  -h|-help)    # help information
					   echo ""
					   usage2
					   exit 0
					   ;;
				-r)    # get radii
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID RADII SPECIFICATION ---"
					   checkMinus "$1"
					   radii=`expr "$1" : '\([,.0-9]*\)'`
					   [ "$radii" = "" ] && errMsg "--- RADII=$radii MUST BE TWO COMMA SEPARATED NON-NEGATIVE FLOAT ---"
 					   ;;
				-t)    # get transparency alphas
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID TRANSPARENCY SPECIFICATION ---"
					   checkMinus "$1"
					   alphas=`expr "$1" : '\([,.0-9]*\)'`
					   [ "$alphas" = "" ] && errMsg "--- TRANSPARENCY=$alphas MUST BE TWO COMMA SEPARATED NON-NEGATIVE FLOAT ---"
 					   ;;
				-w)    # get weights
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID WEIGHTS SPECIFICATION ---"
					   checkMinus "$1"
					   weights=`expr "$1" : '\([,.0-9]*\)'`
					   [ "$weights" = "" ] && errMsg "--- WEIGHTS=$weights MUST BE TWO COMMA SEPARATED NON-NEGATIVE FLOAT ---"
 					   ;;
				-b)    # get bias
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID BIAS SPECIFICATION ---"
					   checkMinus "$1"
					   bias=`expr "$1" : '\([.0-9]*\)'`
					   [ "$bias" = "" ] && errMsg "--- BIAS=$bias MUST BE A NON-NEGATIVE FLOAT ---"
					   test1=`echo "$bias <= 0" | bc`
					   test2=`echo "$bias >= 100" | bc`
					   [ $test1 -eq 1 -o $test2 -eq 1 ] && errMsg "--- BIAS=$bias MUST BE FLOAT GREATER THAN 0 AND LESS THAN 100 ---"
 					   ;;
				-c)    # get compose
					   shift  # to get the next parameter
					   # test if parameter starts with minus sign 
					   #errorMsg="--- INVALID COMPOSE SPECIFICATION ---"
					   #checkMinus "$1"
					   compose=`expr "$1" : '\([-_,a-z,A-Z]*\)'`
					   [ "$compose" = "" ] && errMsg "--- COMPOSE=$compose MUST BE TWO COMMA DELIMITED COMPOSE METHODS ---"
					   ;;
			 	-)    # STDIN and end of arguments
					   break
					   ;;
				-*)    # any other - argument
					   errMsg "--- UNKNOWN OPTION ---"
					   ;;
		     	 *)    # end of arguments
					   break
					   ;;
			esac
			shift   # next option
	done
	#
	# get infile and outfile
	infile="$1"
	outfile="$2"
fi

# test that infile provided
[ "$infile" = "" ] && errMsg "NO INPUT FILE SPECIFIED"

# test that outfile provided
[ "$outfile" = "" ] && errMsg "NO OUTPUT FILE SPECIFIED"

# extract pairs from arguments
rad1=`echo $radii | cut -d, -f 1`
rad2=`echo $radii | cut -d, -f 2`
alpha1=`echo $alphas | cut -d, -f 1`
alpha2=`echo $alphas | cut -d, -f 2`
wt1=`echo $weights | cut -d, -f 1`
wt2=`echo $weights | cut -d, -f 2`
compose1=`echo $compose | cut -d, -f 1`
compose2=`echo $compose | cut -d, -f 2`

# test that two values specified from arguments
[ "$rad1" = "" -o "$rad2" = "" ] && errMsg "--- TWO RADII MUST BE SPECIFIED ---"
[ "$alpha1" = "" -o "$alpha2" = "" ] && errMsg "--- TWO TRANSPARENCIES MUST BE SPECIFIED ---"
[ "$wt1" = "" -o "$wt2" = "" ] && errMsg "--- TWO WEIGHTS MUST BE SPECIFIED ---"
[ "$compose1" = "" -o "$compose2" = "" ] && errMsg "--- TWO COMPOSE METHODS MUST BE SPECIFIED ---"

# set up temp files
tmpA1="$dir/enrich_A_$$.mpc"
tmpA2="$dir/enrich_A_$$.cache"
trap "rm -f $tmpA1 $tmpA2;" 0
trap "rm -f $tmpA1 $tmpA2; exit 1" 1 2 3 15
trap "rm -f $tmpA1 $tmpA2; exit 1" ERR

# read the input image into the temp files and test validity.
convert -quiet "$infile" -alpha off +repage "$tmpA1" ||
	errMsg "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE  ---"

# change sign on wt2
wt2=-$wt2

# change bias from percent to range 0 to 1
bias=`convert xc: -format "%[fx:$bias/100]" info:`

# get IM version
im_version=`convert -list configure | \
	sed '/^LIB_VERSION_NUMBER */!d; s//,/;  s/,/,0/g;  s/,0*\([0-9][0-9]\)/\1/g' | head -n 1`

# note -evaluate set seems to change the opacity whether -channel A means opacity (before IM 6.7.6.8) or transparency thereafter
# however, at IM 6.7.6.8 -channel a became transparency and not opacity
if [ "$im_version" -ge "06070608" ]; then
	negating="-negate"
else
	negating=""
fi
negating=""
#echo "neg=$negating"

# speed up larger radius blur by resizing down, using smaller blur and resizing back up
rad1=`convert xc: -format "%[fx:$rad1/5]" info:`
ww=`convert $tmpA1 -format "%w" info:`
hh=`convert $tmpA1 -format "%h" info:`

convert $tmpA1 \
\( -clone 0 -resize 20% -blur 0x$rad1 -resize ${ww}x${hh}\! \) \
\( -clone 0 -clone 1 +swap -compose mathematics \
-set option:compose:args "0,$wt1,$wt2,$bias" -composite \
-alpha on -channel A $negating -evaluate set ${alpha1}% +channel \) \
\( -clone 0 -blur 0x$rad2 \) \
\( -clone 0 -clone 3 +swap -compose mathematics \
-set option:compose:args "0,$wt1,$wt2,$bias" -composite \
-alpha on -channel A $negating -evaluate set ${alpha2}% +channel \) \
\( -clone 0 -clone 2 -compose $compose1 -composite \
-clone 4 -compose $compose2 -composite \) \
-delete 0-4 "$outfile"

exit 0

