You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
			
		
		
		
			
				
					373 lines
				
				13 KiB
			
		
		
			
		
	
	
					373 lines
				
				13 KiB
			| 
											9 months ago
										 | #!/bin/bash
 | ||
|  | #
 | ||
|  | # Developed by Fred Weinhaus 2/24/2022 .......... revised 2/24/2022
 | ||
|  | #
 | ||
|  | # ------------------------------------------------------------------------------
 | ||
|  | # 
 | ||
|  | # 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: position [-m method] [-d direction] [-o offset] [-l leftpt] 
 | ||
|  | # [-r rightpt] [-b bcolor] [-f format] [-T trim] infile1 infile2 outfile
 | ||
|  | #
 | ||
|  | # USAGE: position [-h or -help]
 | ||
|  | #
 | ||
|  | # OPTIONS:
 | ||
|  | #
 | ||
|  | # -m     method        positioning method; choices are: offset or cpoints; 
 | ||
|  | #                      default=offset
 | ||
|  | # -d     direction     positioning direction; choices are: horizontal or 
 | ||
|  | #                      vertical; default=horizontal
 | ||
|  | # -o     offset        offset +X+Y values for left/ope edge of second image  
 | ||
|  | #                      relative to right/bottom edge of first image. Used when 
 | ||
|  | #                      method=offset; positive or negative offsets are allowed; 
 | ||
|  | #                      default=+0+0
 | ||
|  | # -l     leftpt        left (first) image control x,y point; default=0,0
 | ||
|  | # -r     rightpt       right (second) image control x,y point; default=0,0
 | ||
|  | # -b     bcolor        background color to fill empty spaces
 | ||
|  | # -f     format        output color format; choices are: RG, GB, BR or RGB; 
 | ||
|  | #                      default=RGB
 | ||
|  | # -T     trim          trim output to remove any background fill areas
 | ||
|  | #
 | ||
|  | ###
 | ||
|  | #
 | ||
|  | # NAME: POSITION 
 | ||
|  | # 
 | ||
|  | # PURPOSE: To position one image relative to another image.
 | ||
|  | # 
 | ||
|  | # DESCRIPTION: POSITION aligns or offsets one image relative to a another 
 | ||
|  | # image.  The second image is positioned relative to the first image either 
 | ||
|  | # horizontally or vertically. Positioning can be done using X and Y offsets 
 | ||
|  | # or by specifying one controll point for each image.
 | ||
|  | # 
 | ||
|  | # OPTIONS: 
 | ||
|  | #
 | ||
|  | # -m method ... positioning METHOD. The choices are: offset (o) or cpoints (c).
 | ||
|  | # The default=offset.
 | ||
|  | # 
 | ||
|  | # -d direction ... positioning DIRECTION. The choices are: horizontal (h) or 
 | ||
|  | # vertical (v). The default=horizontal.
 | ||
|  | # 
 | ||
|  | # -o offset ... OFFSET +X+Y values for left/top edge of second image relative 
 | ||
|  | # to right/bottom edge of first image. This is used when method=offset. 
 | ||
|  | # Position X and Y offsets may be either positive or negative. The default=+0+0
 | ||
|  | # 
 | ||
|  | # -l leftpt ... LEFT (first) image control x,y POINT. Values are integers>0. 
 | ||
|  | # The default=0,0
 | ||
|  | # 
 | ||
|  | # -r rightpt ... RIGHT (second) image control x,y POINT. Values are integers>0. 
 | ||
|  | # The default=0,0
 | ||
|  | # 
 | ||
|  | # -b bcolor ... BGCOLOR is the background color to fill empty spaces. Any 
 | ||
|  | # Imagemagick color is allowed. The default=none (transparent)
 | ||
|  | # 
 | ||
|  | # -f format ... output color FORMAT; The choices are: RG, GB, BR or RGB. 
 | ||
|  | # RGB is the normal color image. RG, for example, is first image in Red and 
 | ||
|  | # second image in Green and any overlay will show in yellow (mix of Red and 
 | ||
|  | # Green). The default=RGB.
 | ||
|  | # 
 | ||
|  | # -T trim ... TRIM output to remove any background fill areas.
 | ||
|  | # Choices are: yes (y) or no (n). The default=no. Background color must be 
 | ||
|  | # unique in the image for the trim to work properly.
 | ||
|  | # 
 | ||
|  | # LIMITATIONS: TRIM option only works for Imagemagick 7.0.9-0 or higher.
 | ||
|  | # 
 | ||
|  | # 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
 | ||
|  | method="offset"            # offset or cpoints
 | ||
|  | direction="horizontal"     # horizontal or vertical
 | ||
|  | offset=+0+0                # offset
 | ||
|  | #offset=-90-40             # offset
 | ||
|  | leftpt="0,0"               # left image single control point
 | ||
|  | rightpt="0,0"              # right image single control point
 | ||
|  | #leftpt="287,49"           # left image single control point
 | ||
|  | #rightpt="76,89"           # right image single control point
 | ||
|  | bcolor=none                # background color
 | ||
|  | format="RGB"               # RG or GB or BR or RGB output color format
 | ||
|  | trim="no"                  # trim output; yes or no
 | ||
|  | 
 | ||
|  | # set directory for temporary files
 | ||
|  | tmpdir="/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 19 ]
 | ||
|  | 	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)    # method
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID METHOD SPECIFICATION ---"
 | ||
|  | 					   checkMinus "$1"
 | ||
|  | 					   method=`echo "$1" | tr "[:upper:]" "[:lower:]"`
 | ||
|  | 					   case "$method" in 
 | ||
|  | 							offset|o) method="offset" ;;
 | ||
|  | 							cpoints|c) method="cpoints" ;;
 | ||
|  | 							*) errMsg "--- METHOD=$method IS AN INVALID VALUE ---" 
 | ||
|  | 					   esac
 | ||
|  | 				   	   ;;
 | ||
|  | 				-d)    # direction
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID DIRECTION SPECIFICATION ---"
 | ||
|  | 					   checkMinus "$1"
 | ||
|  | 					   direction=`echo "$1" | tr "[:upper:]" "[:lower:]"`
 | ||
|  | 					   case "$direction" in 
 | ||
|  | 							horizontal|h) direction="horizontal" ;;
 | ||
|  | 							vertical|v) direction="vertical" ;;
 | ||
|  | 							*) errMsg "--- DIRECTION=$direction IS AN INVALID VALUE ---" 
 | ||
|  | 					   esac
 | ||
|  | 				   	   ;;
 | ||
|  | 				-o)    # offset
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID OFFSET SPECIFICATION ---"
 | ||
|  | 					   #checkMinus "$1"
 | ||
|  | 					   offset=`expr "$1" : '\([-+][0-9]*[-+][0-9]*\)'`
 | ||
|  | 					   [ "$offset" = "" ] && errMsg "--- OFFSET=$offset IS INVALID ---"
 | ||
|  | 					   ;;
 | ||
|  | 				-l)    # leftpt
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID LEFTPT SPECIFICATION ---"
 | ||
|  | 					   checkMinus "$1"
 | ||
|  | 					   leftpt=`expr "$1" : '\([0-9]*,[0-9]*\)'`
 | ||
|  | 					   [ "$leftpt" = "" ] && errMsg "--- LEFTPT=$leftpt IS INVALID ---"
 | ||
|  | 					   ;;
 | ||
|  | 				-r)    # rightpt
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID RIGHTPT SPECIFICATION ---"
 | ||
|  | 					   checkMinus "$1"
 | ||
|  | 					   rightpt=`expr "$1" : '\([0-9]*,[0-9]*\)'`
 | ||
|  | 					   [ "$rightpt" = "" ] && errMsg "--- RIGHTPT=$rightpt IS INVALID ---"
 | ||
|  | 					   ;;
 | ||
|  | 				-b)    # bcolor
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID BCOLOR SPECIFICATION ---"
 | ||
|  | 					   checkMinus "$1"
 | ||
|  | 					   bcolor="$1"
 | ||
|  | 					   ;;
 | ||
|  | 				-f)    # format
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID FORMAT SPECIFICATION ---"
 | ||
|  | 					   checkMinus "$1"
 | ||
|  | 					   format=`echo "$1" | tr "[:lower:]" "[:upper:]"`
 | ||
|  | 					   case "$format" in 
 | ||
|  | 							RG) ;;
 | ||
|  | 							GB) ;;
 | ||
|  | 							BR) ;;
 | ||
|  | 							RGB) ;;
 | ||
|  | 							*) errMsg "--- FORMAT=$format IS AN INVALID VALUE ---" 
 | ||
|  | 					   esac
 | ||
|  | 				   	   ;;
 | ||
|  | 				-T)    # trim
 | ||
|  | 					   shift  # to get the next parameter
 | ||
|  | 					   # test if parameter starts with minus sign 
 | ||
|  | 					   errorMsg="--- INVALID TRIM SPECIFICATION ---"
 | ||
|  | 					   checkMinus "$1"
 | ||
|  | 					   trim=`echo "$1" | tr "[:upper:]" "[:lower:]"`
 | ||
|  | 					   case "$trim" in 
 | ||
|  | 							yes) ;;
 | ||
|  | 							no) ;;
 | ||
|  | 							*) errMsg "--- TRIM=$trim IS AN INVALID VALUE ---" 
 | ||
|  | 					   esac
 | ||
|  | 				   	   ;;
 | ||
|  | 				 -)    # STDIN and end of arguments
 | ||
|  | 					   break
 | ||
|  | 					   ;;
 | ||
|  | 				-*)    # any other - argument
 | ||
|  | 					   errMsg "--- UNKNOWN OPTION ---"
 | ||
|  | 					   ;;
 | ||
|  | 		     	 *)    # end of arguments
 | ||
|  | 					   break
 | ||
|  | 					   ;;
 | ||
|  | 			esac
 | ||
|  | 			shift   # next option
 | ||
|  | 	done
 | ||
|  | 	#
 | ||
|  | 	# get infiles and outfile
 | ||
|  | 	infile1="$1"
 | ||
|  | 	infile2="$2"
 | ||
|  | 	outfile="$3"
 | ||
|  | fi
 | ||
|  | 
 | ||
|  | # test that infile1 provided
 | ||
|  | [ "$infile1" = "" ] && errMsg "--- NO INPUT FILE 1 SPECIFIED ---"
 | ||
|  | 
 | ||
|  | # test that infile2 provided
 | ||
|  | [ "$infile2" = "" ] && errMsg "--- NO INPUT FILE 2 SPECIFIED ---"
 | ||
|  | 
 | ||
|  | # test that outfile provided
 | ||
|  | [ "$outfile" = "" ] && errMsg "--- NO OUTPUT FILE SPECIFIED ---"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | dir="$tmpdir/POSITION.$$"
 | ||
|  | 
 | ||
|  | mkdir "$dir" || echo "--- FAILED TO CREATE TEMPORARY FILE DIRECTORY ---"
 | ||
|  | trap "rm -rf $dir; exit 0" 0
 | ||
|  | trap "rm -rf $dir; exit 1" 1 2 3 15
 | ||
|  | 
 | ||
|  | # read input images
 | ||
|  | # test if infile exists, is readable and is not zero size
 | ||
|  | convert -quiet "$infile1" +repage $dir/tmpI1.mpc || 
 | ||
|  | 	echo  "--- FILE $infile1 DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE  ---"
 | ||
|  | 
 | ||
|  | convert -quiet "$infile2" +repage $dir/tmpI2.mpc || 
 | ||
|  | 	echo  "--- FILE $infile2 DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE  ---"
 | ||
|  | 
 | ||
|  | # get image1 dimensions
 | ||
|  | ww=`convert  $dir/tmpI1.mpc -format "%w" info:`
 | ||
|  | hh=`convert  $dir/tmpI1.mpc -format "%h" info:`
 | ||
|  | #echo "ww=$ww; hh=$hh;"
 | ||
|  | 
 | ||
|  | # get page values for second image
 | ||
|  | if [ "$method" = "cpoints" ]; then
 | ||
|  | 	lx=`echo "$leftpt" | cut -d, -f1`
 | ||
|  | 	ly=`echo "$leftpt" | cut -d, -f2`
 | ||
|  | 	rx=`echo "$rightpt" | cut -d, -f1`
 | ||
|  | 	ry=`echo "$rightpt" | cut -d, -f2`
 | ||
|  | 		pagex=$((lx-rx))
 | ||
|  | 		pagey=$((ly-ry))
 | ||
|  | 	
 | ||
|  | else # offsets
 | ||
|  | 	xoff=`echo $offset | sed -n 's/^\([+-].*\)[+-].*$/\1/p'`
 | ||
|  | 	yoff=`echo $offset | sed -n 's/^[+-].*\([+-].*\)$/\1/p'`
 | ||
|  | 	if [ "$direction" = "horizontal" ]; then
 | ||
|  | 		pagex=$((ww+xoff))
 | ||
|  | 		pagey=$((yoff))
 | ||
|  | 	else 
 | ||
|  | 		# vertical
 | ||
|  | 		pagex=$((xoff))
 | ||
|  | 		pagey=$((hh+yoff))
 | ||
|  | 	fi
 | ||
|  | fi
 | ||
|  | #echo "ww=$ww; hh=$hh; xoff=$xoff; yoff=$yoff; lx=$lx; ly=$ly; rx=$rx; ry=$ry; pagex=$pagex; pagey=$pagey;"
 | ||
|  | 
 | ||
|  | # set up for trim
 | ||
|  | [ "$trim" = "yes" ] && trimming="-background $bcolor -define trim:percent-background=0% -trim +repage"
 | ||
|  | 
 | ||
|  | # align the two images
 | ||
|  | if [ "$format" = "RG" ]; then
 | ||
|  | 	convert \
 | ||
|  | 		\( $dir/tmpI1.mpc -colorspace gray -set page +0+0 -write mpr:img1 +delete \) \
 | ||
|  | 		\( $dir/tmpI2.mpc -colorspace gray -set page +${pagex}+${pagey} -write mpr:img2 +delete \) \
 | ||
|  | 		\( \( mpr:img2 -background black -colorize 100 \) \( mpr:img1 +level-colors "black,red" \) \
 | ||
|  | 			-background "$bcolor" -layers merge +repage \) \
 | ||
|  | 		\( \( mpr:img1 -background black -colorize 100 \) \( mpr:img2 +level-colors "black,green1" \) \
 | ||
|  | 			-background "$bcolor" -layers merge +repage \) \
 | ||
|  | 		-compose over -compose blend -composite $trimming \
 | ||
|  | 		"$outfile"
 | ||
|  | 
 | ||
|  | elif [ "$format" = "GB" ]; then
 | ||
|  | 	convert \
 | ||
|  | 		\( $dir/tmpI1.mpc -colorspace gray -set page +0+0 -write mpr:img1 +delete \) \
 | ||
|  | 		\( $dir/tmpI2.mpc -colorspace gray -set page +${pagex}+${pagey} -write mpr:img2 +delete \) \
 | ||
|  | 		\( \( mpr:img2 -background black -colorize 100 \) \( mpr:img1 +level-colors "black,green1" \) \
 | ||
|  | 			-background "$bcolor" -layers merge +repage \) \
 | ||
|  | 		\( \( mpr:img1 -background black -colorize 100 \) \( mpr:img2 +level-colors "black,blue" \) \
 | ||
|  | 			-background "$bcolor" -layers merge +repage \) \
 | ||
|  | 		-compose over -compose blend -composite $trimming \
 | ||
|  | 		"$outfile"
 | ||
|  | 
 | ||
|  | elif [ "$format" = "BR" ]; then
 | ||
|  | 	convert \
 | ||
|  | 		\( $dir/tmpI1.mpc -colorspace gray -set page +0+0 -write mpr:img1 +delete \) \
 | ||
|  | 		\( $dir/tmpI2.mpc -colorspace gray -set page +${pagex}+${pagey} -write mpr:img2 +delete \) \
 | ||
|  | 		\( \( mpr:img2 -background black -colorize 100 \) \( mpr:img1 +level-colors "black,blue" \) \
 | ||
|  | 			-background "$bcolor" -layers merge +repage \) \
 | ||
|  | 		\( \( mpr:img1 -background black -colorize 100 \) \( mpr:img2 +level-colors "black,red" \) \
 | ||
|  | 			-background "$bcolor" -layers merge +repage \) \
 | ||
|  | 		-compose over -compose blend -composite $trimming \
 | ||
|  | 		"$outfile"
 | ||
|  | 
 | ||
|  | else # RGB
 | ||
|  | 	convert \
 | ||
|  | 		\( $dir/tmpI1.mpc -set page +0+0 \) \
 | ||
|  | 		\( $dir/tmpI2.mpc -set page +${pagex}+${pagey} \) \
 | ||
|  | 		-background "$bcolor" -layers merge +repage $trimming \
 | ||
|  | 		"$outfile"
 | ||
|  | 		
 | ||
|  | 
 | ||
|  | fi
 | ||
|  | 
 | ||
|  | exit 0
 |