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.
		
		
			
		
		
		
		
			
		
			
				
					
					
						
							372 lines
						
					
					
						
							13 KiB
						
					
					
				
			
		
		
	
	
							372 lines
						
					
					
						
							13 KiB
						
					
					
				| #!/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
 | |
| 
 |