#!/bin/bash -x ##################### #### Create two ripples of various sizes in a picture one on each half #### of the screen. Uses imagemagick and its depolar and polar distort #### commands, the displace command, a lot of compositing and #### more. Use files from one input folder or an intermediate file #### from another composition script and put sequentially numbered #### output files to one outfolder. This script requires two files, #### vectors-right and vectors-left. The vector files are a sequence #### of file sizes by which to decide the size of the current #### ripple. Based on ripples script by Fred Weinhaus #### http://www.fmwconcepts.com/imagemagick/index.html. ####################### trap "rm -f *.list *.mpc *.cache" 1 2 3 15 trap "exit 0" 2 #range within which number the position of the ripples should be picked RandomGenerator () { RANGE=$2 FLOOR=$1 # Picks a number between the floor and range number=0 #initialize while [ "$number" -le $FLOOR ] do number=$RANDOM let "number %= $RANGE" # Scales $number down within $RANGE. done } RippleDefault () { total_left_ripple=43 # Duration of left ripple total_right_ripple=40 # Duration of right ripple # Defaults that need to be set at the beginning, but will change throughout the effect RIGHT_RIPPLE_NUMBER=1 # Line to call in vector file LEFT_RIPPLE_NUMBER=1 # Line to call in vector file # Writes default to file, so that they can be exported as variables from the parent process. echo -e "export total_left_ripple=$total_left_ripple \n export total_right_ripple=$total_right_ripple ">defaults-ripple.list } RippleRightDefault () { INNER_RIGHT=5 # Width of the initial "drop" of the ripple SIZE_RIGHT=`awk 'NR=='$RIGHT_RIPPLE_NUMBER' {print $2}' vectors-right` # Awks vector file SIZE_RIGHT=$(echo " $WIDTH * $SIZE_RIGHT " | bc) # Percentage of file-width of ripple GRADIENT_RIGHT=$(echo "scale=2; ( $SIZE_RIGHT * 0.42 ) - $INNER_RIGHT " | bc) # Width of the ripple OUTER_RIGHT=$(echo "scale=2; $SIZE_RIGHT * 0.58 " | bc) # Width of outer calm side of the ripple OUTER2_RIGHT=$OUTER_RIGHT # SLOW DOWN RIPPLES BY MAKING OUTER2_RIGHT SMALLER MID_CIRC_RIGHT=$(echo " $SIZE_RIGHT / 2 " | bc) # Mid point of square where the ripple takes place RAD_RIGHT=$(echo " $MID_CIRC_RIGHT / 5 " | bc) # Radius of cookie cut where the ripple will occur X_POS_RIGHT=$(echo " $WIDTH - $SIZE_RIGHT " | bc) # Range of possible X positions for the ripple Y_POS_RIGHT=$(echo " $BOTTOM - $SIZE_RIGHT " | bc) # Range of Possible Y positions of the ripple X_POS_RIGHT=$(echo $X_POS_RIGHT | awk '{printf "%.0f",$1}') # Removes floating point for random generator Y_POS_RIGHT=$(echo $Y_POS_RIGHT | awk '{printf "%.0f",$1}') # Removes floating point for random generator RandomGenerator $MID $X_POS_RIGHT GEOX_RIGHT=$number # Right position along the x axis where ripple takes place RandomGenerator 0 $Y_POS_RIGHT GEOY_RIGHT=$number # Top position along the y axis where ripple takes place COUNT_RIPPLES_RIGHT=1 # Start count up to total_right_ripple # Write defaults valid throught this ripple echo -e "SIZE_RIGHT=$SIZE_RIGHT \n GRADIENT_RIGHT=$GRADIENT_RIGHT \n OUTER2_RIGHT=$OUTER2_RIGHT \n MID_CIRC_RIGHT=$MID_CIRC_RIGHT \n RAD_RIGHT=$RAD_RIGHT \n GEOX_RIGHT=$GEOX_RIGHT \n GEOY_RIGHT=$GEOY_RIGHT \n RIGHT_RIPPLE_NUMBER=$RIGHT_RIPPLE_NUMBER">right-defaults.list # Remember variables for the next time runthrough echo -e "OUTER_RIGHT=$OUTER_RIGHT \n INNER_RIGHT=$INNER_RIGHT \n COUNT_RIPPLES_RIGHT=$COUNT_RIPPLES_RIGHT">right-variable.list } RippleLeftDefault () { COUNT_RIPPLES_LEFT=1 INNER_LEFT=5 SIZE_LEFT=`awk 'NR=='$LEFT_RIPPLE_NUMBER' {print $2}' vectors-left` SIZE_LEFT=$(echo " $WIDTH * $SIZE_LEFT " | bc) GRADIENT_LEFT=$(echo "scale=2; ( $SIZE_LEFT * 0.42 ) - $INNER_LEFT " | bc) OUTER_LEFT=$(echo "scale=2; $SIZE_LEFT * 0.58 " | bc) OUTER2_LEFT=$OUTER_LEFT MID_CIRC_LEFT=$(echo " $SIZE_LEFT / 2 " | bc) RAD_LEFT=$(echo " $MID_CIRC_LEFT / 5 " | bc) X_POS_LEFT=$(echo " $MID - $SIZE_LEFT " | bc) Y_POS_LEFT=$(echo " $BOTTOM - $SIZE_LEFT " | bc) X_POS_LEFT=$(echo $X_POS_LEFT | awk '{printf "%.0f",$1}') Y_POS_LEFT=$(echo $Y_POS_LEFT | awk '{printf "%.0f",$1}') RandomGenerator 0 $X_POS_LEFT GEOX_LEFT=$number RandomGenerator 0 $Y_POS_LEFT GEOY_LEFT=$number echo -e "SIZE_LEFT=$SIZE_LEFT \n GRADIENT_LEFT=$GRADIENT_LEFT \n OUTER2_LEFT=$OUTER2_LEFT \n MID_CIRC_LEFT=$MID_CIRC_LEFT \n RAD_LEFT=$RAD_LEFT \n GEOX_LEFT=$GEOX_LEFT \n GEOY_LEFT=$GEOY_LEFT \n LEFT_RIPPLE_NUMBER=$LEFT_RIPPLE_NUMBER">left-defaults.list echo -e "OUTER_LEFT=$OUTER_LEFT \n INNER_LEFT=$INNER_LEFT \n COUNT_RIPPLES_LEFT=$COUNT_RIPPLES_LEFT">left-variable.list } # Create gradient mask with sin wave which will be the ripple effect; # is only one dimensional at first; leaves 50% gray space at center # and outer edges where photo remains unrippled. Called twice once for # each side; thus eval is used. The part of the infile where the # ripple is to take place is cropped. Using a depolar distort and # displace the mask and infile are joined. CreateGradient () { eval GRADIENT=\$GRADIENT_$SIDE eval OUTER=\$OUTER_$SIDE eval SIZE=\$SIZE_$SIDE eval GEOX=\$GEOX_$SIDE eval GEOY=\$GEOY_$SIDE eval MID_CIRC=\$MID_CIRC_$SIDE VAR_GRADIENT=$SIDE.mpc eval INNER=\$INNER_$SIDE convert -size 1x$GRADIENT gradient: -evaluate sine 3 \ \( -size 1x$GRADIENT gradient: \) \ -compose Multiply -composite \ \( -size 1x$GRADIENT gradient: -negate -evaluate divide 2 \) \ -compose Plus -composite -size 1x$INNER xc:"gray(50%)" -swap 0 -size 1x$OUTER xc:"gray(50%)" -append -scale "$SIZE"x$SIZE! mask.mpc convert $INFILE +gravity -crop "$SIZE"x$SIZE+$GEOX+$GEOY +repage -distort depolar -1,0,$MID_CIRC,$MID_CIRC miff:- | composite - mask.mpc -swap 0 -displace 0x40 $VAR_GRADIENT } # Using polar distort the image gets its ripple look. Right and left # ripples are composited into the original where blurred holes have # been cut out in the proper positions. RippleEffect () { convert -size "$WIDTH"x$BOTTOM xc:transparent \ \( RIGHT.mpc -distort polar -1,0,$MID_CIRC_RIGHT,$MID_CIRC_RIGHT \) \ -geometry +$GEOX_RIGHT+$GEOY_RIGHT $VAR_RIGHT -composite \ \( LEFT.mpc -distort polar -1,0,$MID_CIRC_LEFT,$MID_CIRC_LEFT \) \ -geometry +$GEOX_LEFT+$GEOY_LEFT $VAR_LEFT -composite \ \( $INFILE \ \( -size "$WIDTH"x$BOTTOM xc:white -page +$GEOX_RIGHT+$GEOY_RIGHT \ \( -size "$SIZE_RIGHT"x$SIZE_RIGHT xc:black -fill white \ -draw "circle $MID_CIRC_RIGHT,$MID_CIRC_RIGHT $MID_CIRC_RIGHT,$RAD_RIGHT" -blur 0x10 -negate \) \ -page +$GEOX_LEFT+$GEOY_LEFT \ \( -size "$SIZE_LEFT"x$SIZE_LEFT xc:black -fill white \ -draw "circle $MID_CIRC_LEFT,$MID_CIRC_LEFT $MID_CIRC_LEFT,$RAD_LEFT" -blur 0x10 -negate \) \ -flatten \) \ -compose copy-opacity -composite \) \ -compose src-over -composite $OUTFILE } # Calls up infile and outfile names from caller.list file created by # call-files script comp_ripple = no when only the ripple is being # process; = yes when two infiles are be processed in the sunset or # tractor composition; = maybe if only one file is processed such as # at the beginning of the sunset composition. Caller () { if [ $comp_ripple = no ]; then INFILE=`awk 'NR==1 {print $1}' caller.list` OUTFILE=`awk 'NR==2' caller.list` elif [ $comp_ripple = yes ]; then INFILE=`awk 'NR==3 {print $1}' caller.list` OUTFILE=`awk 'NR==4' caller.list` else INFILE=`awk 'NR==2' caller.list` OUTFILE=`awk 'NR==3' caller.list` fi } # Recalculate the size of the area inside and outside the ripple to # make it appear to move. Also adds to count up to total_right_ripple RememberRightVariables () { INNER_RIGHT=$(echo "scale=2; $INNER_RIGHT + ( ( $OUTER2_RIGHT + 10 ) / $total_right_ripple ) " | bc) OUTER_RIGHT=$(echo "scale=2; $OUTER_RIGHT - ( $OUTER2_RIGHT / $total_right_ripple ) " | bc) let "COUNT_RIPPLES_RIGHT += 1" echo -e "COUNT_RIPPLES_RIGHT=$COUNT_RIPPLES_RIGHT \n INNER_RIGHT=$INNER_RIGHT \n OUTER_RIGHT=$OUTER_RIGHT">right-variable.list } RememberLeftVariables () { INNER_LEFT=$(echo "scale=2; $INNER_LEFT + ( ( $OUTER2_LEFT + 10 ) / $total_left_ripple ) " | bc) OUTER_LEFT=$(echo "scale=2; $OUTER_LEFT - ( $OUTER2_LEFT / $total_left_ripple ) " | bc) let "COUNT_RIPPLES_LEFT += 1" echo -e "COUNT_RIPPLES_LEFT=$COUNT_RIPPLES_LEFT \n INNER_LEFT=$INNER_LEFT \n OUTER_LEFT=$OUTER_LEFT">left-variable.list } # Processes first frame of ripple and saves defaults for later ripples if [ $COUNT = $DEFAULT_FETCH_RIPPLES ]; then Caller RippleDefault RippleRightDefault RippleLeftDefault SIDE=RIGHT # mask process for right side CreateGradient SIDE=LEFT # mask process for left side CreateGradient RippleEffect RememberRightVariables RememberLeftVariables else . right-defaults.list # Remembers various defaults and variables . left-defaults.list . right-variable.list . left-variable.list Caller SIDE=RIGHT CreateGradient SIDE=LEFT CreateGradient RippleEffect if [ $COUNT_RIPPLES_LEFT -lt $total_left_ripple ]; then RememberLeftVariables # once duration is done a new position and size is chosen else let "LEFT_RIPPLE_NUMBER += 1" RippleLeftDefault fi # The left and right sides have different durations thus there is a phase shift. if [ $COUNT_RIPPLES_RIGHT -lt $total_right_ripple ]; then RememberRightVariables else let "RIGHT_RIPPLE_NUMBER += 1" RippleRightDefault fi fi