#!/bin/bash
#
# Developed by Fred Weinhaus 6/1/2008 .......... revised 6/2/2015
#
# ------------------------------------------------------------------------------
# 
# 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: variableblur [-m maxblur] [-n numblurs] infile maskfile outfile
# USAGE: variableblur [-h or -help]
#
# OPTIONS:
#
# -m      maxblur         maximum blur amount in pixels; integer>1;
#                         recommend even values; default=16
# -n      numblurs        number of blur increments; 2<=integer<maxblur;
#                         default=maxblur-1
#
###
#
# NAME: VARIABLEBLUR 
# 
# PURPOSE: To apply a variable blur to an image based upon a mask image.
# 
# DESCRIPTION: VARIABLEBLUR applies a variable blur to an image based 
# upon a mask image. The brighter the mask image the larger the blur.
# Limiting factors are determined by the user supplied parameters: 
# maxblur and numblurs. This is most useful when the mask is a radial 
# gradient. It then blurs around the main subject of the image.
# 
# OPTIONS: 
# 
# -m maxblur ... MAXBLUR is the maximum amount of blur in pixels when the 
# mask image is fully white. No blur is applied where the image is 
# fully black. Values must be integers>1. Typical values are less than 
# or equal to 32. The default is 16.
#
# -n numblurs ... NUMBLURS is the number of evenly spaced blur increments 
# up to maxblur. Values are integers between 2 and maxblur-1. 
# The default=maxblur-1. For improved performance with slight loss 
# of quality when maxblur is large, use numblurs=maxblur/2.
#
# 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
maxblur=16
numblurs=""

# 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 7 ]
	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
					   ;;
				-m)    # get maxblur
					   shift  # to get the next parameter - maxblur
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID MAXBLUR SPECIFICATION ---"
					   checkMinus "$1"
					   maxblur=`expr "$1" : '\([0-9]*\)'`
					   [ "$maxblur" = "" ] && errMsg "MAXBLUR=$maxblur MUST BE AN INTEGER"
		   			   maxblurtestA=`echo "$maxblur < 2" | bc`
					   [ $maxblurtestA -eq 1 ] && errMsg "--- MAXBLUR=$maxblur MUST BE AN INTEGER GREATER THAN 1 ---"
					   ;;
				-n)    # get numblurs
					   shift  # to get the next parameter - numblurs
					   # test if parameter starts with minus sign 
					   errorMsg="--- INVALID NUMBLURS SPECIFICATION ---"
					   checkMinus "$1"
					   numblurs=`expr "$1" : '\([0-9]*\)'`
					   [ "$numblurs" = "" ] && errMsg "NUMBLURS=$numblurs MUST BE AN INTEGER"
		   			   numblurstestA=`echo "$numblurs < 2" | bc`
					   [ $numblurstestA -eq 1 ] && errMsg "--- NUMBLURS=$numblurs MUST BE AN INTEGER GREATER THAN 1 ---"
					   ;;
				 -)    # 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"
	maskfile="$2"
	outfile="$3"
fi

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

# test that maskfile provided
[ "$maskfile" = "" ] && errMsg "NO MASKFILE SPECIFIED"

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

# test that numblurs < maxblur and set to maxblur-1 if no value
if [ "$numblurs" = "" ]
	then
	numblurs=`expr $maxblur - 1`
else
	[ $numblurs -ge $maxblur ] && errMsg "--- NUMBLURS MUST BE LESS THAN MAXBLUR ---"
fi

# set temporary files
# create tmpdir directory
tmpdir=$dir/varblur.$$
mkdir $tmpdir
# test if created successfully
if [ $? -ne 0 ]; then
echo >&2 "$PROGNAME: Failed to create directory \"$tmpdir\" -- ABORTING"
exit 1
fi
# create tmp files in tmpdir
for ((i=0;i<=$numblurs;i++))
	do
    eval tmp$i='"$tmpdir/varblur_'$i'_$.miff"'
done
tmpM="$tmpdir/varblur_M_$.miff"
# remove tmpdir and all file contained in it
trap "rm -rf $tmpdir;" 0
trap "rm -rf $tmpdir; exit 1" 1 2 3 15
trap "rm -rf $tmpdir; exit 1" ERR


if convert -quiet "$infile" +repage "$tmp0"
	then
	: ' Do Nothing '
else
	errMsg "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---"
fi

if convert -quiet "$maskfile" +repage "$tmpM"
	then
	: ' Do Nothing '
else
	errMsg "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---"
fi

[ $numblurs -ge $maxblur ] && errMsg "--- NUBLURS MUST BE LESS THAN MAXBLUR ---"

ww=`convert $tmp0 -format "%w" info:`
hh=`convert $tmp0 -format "%h" info:`

blurinc=`convert xc: -format "%[fx:$maxblur/$numblurs]" info:`

# create blurred versions of image
images="$tmp0"
blur=$blurinc
j=1
while [ $j -le $numblurs ]
	do
	eval img=\$tmp$j
	max=`convert xc: -format "%[fx:100*$blur]" info:`
	min=`convert xc: -format "%[fx:100/$blur]" info:`
	echo ""
	echo $j
	echo "blur=$blur"
	echo "min=$min"
	echo "max=$max"
	convert $tmp0 -filter box -resize $min% -filter lanczos -resize ${ww}x${hh}! $img
	images="$images $img"
	blur=`convert xc: -format "%[fx:$blur + $blurinc]" info:`
	blurc=`convert xc: -format "%[fx:ceil($blur)]" info:`
	if [ $blurc -gt $maxblur ]
		then
		break
	fi
	j=`expr $j + 1`
done

images="$images $tmpM"

count=$j
count1=`expr $j + 1`

# blend blurred versions
convert $images -monitor \
	-fx "aa=$count*u[$count1]; xx=floor(aa); ff=aa-xx; yy=xx+1; u[xx]+ff*(u[yy]-u[xx])" "$outfile"
exit 0




