#!/bin/bash -x # # Copyright Rob Homsi 2/3/2009 # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. This program is distributed in # the hope that it will be useful, but WITHOUT ANY WARRANTY; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more # details. You should have received a copy of the GNU General Public # License along with this program. If not, see # . # # Based on Fred Weinhaus's transitions http://www.fmwconcepts.com/imagemagick/transitions/index.php # Developed by Fred Weinhaus 5/29/2008 .......... revised 6/4/2008 # If you redistribute or incorporate this script into other free # applications, you may use this scripts by simply referencing Fred's # name and his web page: Fred Weinhaus and # http://www.fmwconcepts.com/imagemagick/index.html. # # USAGE: wipe [-a mask] [-m mode] [-f frames] [-d delay] [-p pause] [-r] [-e] infolder1 infolder2 [outfile] [outfolder] # USAGE: wipe [-h or -help] # # OPTIONS: # # -a mask type of mask file to use: gradient, radial, shutters, noise, blurred, blurrier, plasma, # alternating; default=gradient # -m mode mode of transition; wipe or dissolve; default=wipe # -f frames number of frames in animation; frames>1; default is the number of images in the larger folder. # -d delay delay between frames; delay>0; default=20 (only for outfile) # -p pause Pre and post run the animation this many frames both before and after the transition; # pause>0; default=5 # -r reverse the animation sequence and append it to the end (only for outfile) # -e exponentiate maskfile to make the animation # start more gradually. Mostly useful for mode=dissolve # # The files in two input folders must have the same frame size. # Files in the input folder must be png and named # 001.png, 002.png, 003.png etc... only 999 files are allowed. # # There may only be an outfile or an outfolder # # The output file must be of type that supports multi-frames, such as # gif. If an outfolder is chosen then png files will be outputted into # it. # # If no output file/folder is specified, the animation will be # displayed automatically but not saved to a file # ### # # NAME: WIPE # # PURPOSE: To apply an animated transition between two sets of images. # # DESCRIPTION: WIPE applies an animated transition between two # sets of images using a mask image to control the transition. The # first set of images will show where the mask is black and the second # set of images will show where the mask is white. The mask will be # made gradually more an more white as each frame is composited. NOTE # that this is not a true warping morph. It is simply an animated # masked composite. # # OPTIONS: # # -a mask ... MASK file type. What the transition will look like depends # on the mask file. gradient, radial, shutters, noise, blurred, blurrier, # plasma, alternating. see http://www.fmwconcepts.com/imagemagick/transitions/index.php # for a preview of the various masks. Defaults to gradient. # # -m mode ... MODE of transition. Values are wipe or dissolve. The default is wipe. # Note that dissolve is generally only useful for very gradual graylevel changes # in the mask image, such as in gradient or radial. # # -f frames ... FRAMES is the total number of frames in the # animation. Values are integers > 1. The default is the number of # files in the larger folder. The folder with less images will be # looped. If there are more frames required then there are images in # the folders, then both folders will be looped. If the number of # frames needed is less than the number of images in a folder, than # excess images will be left out. Bear in mind PAUSE will be # subtracted from this number before and after the transition. # # -d delay ... DELAY between frames. Values are integers>0. The # default=20 (only for outfiles such as gifs) # # -p pause ... PAUSE is the number of images in the infolder1 allowed # to play before the transition begins, as well as the number of # images in infolder2 allowed to play after the transition is # over. The default=5 # # -r ... If supplied, then reverse the animation sequence, remove the first and # last frames of the reversed sequence and append these reversed frames to # the end of the animation. (only for outfiles such as gifs) # # -e ... If supplied, then the maskfile will be exponentiated to make the # animation start more gradually. This is useful for most dissolve mode # transitions. # # 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 mode="wipe" #wipe or dissolve delay=20 pause=5 expo="linear" #linear or exponential reverse="no" view="no" frames=1 mask="gradient" # 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 -n '/^###/q; /^#/!q; s/^#//; s/^ //; 4,$p' "$PROGDIR/$PROGNAME" } usage2() { echo >&2 "" echo >&2 "$PROGNAME:" "$@" sed >&2 -n '/^######/q; /^#/!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 14 ] 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 ;; -a) # select type of mask file gradient, radial, etc... shift errMsg="--- INVALID MASK SPECIFICATION ---" mask=$1 case $mask in gradient | radial | shutters | noise | blurred | blurrier | plasma | alternating) ;; *) errMsg "MASK=$mask MASK MUST BE: gradient OR radial OR shutters OR noise OR blurred OR blurrier OR plasma OR alternating ---" ;; esac ;; -m) # get mode shift # to get the next parameter - mode # test if parameter starts with minus sign errorMsg="--- INVALID MODE SPECIFICATION ---" checkMinus "$1" mode="$1" [ "$mode" != "wipe" -a "$mode" != "dissolve" ] && errMsg "MODE=$mode MUST BE EITHER WIPE OR DISSOLVE ---" ;; -f) # get frames shift # to get the next parameter - frames # test if parameter starts with minus sign errorMsg="--- INVALID FRAMES SPECIFICATION ---" checkMinus "$1" frames=`expr "$1" : '\([0-9]*\)'` [ "$frames" = "" ] && errMsg "FRAMES=$frames MUST BE AN INTEGER" framestest=`echo "$frames <= 1" | bc` [ $framestest -eq 1 ] && errMsg "--- FRAMES=$frames MUST BE AN INTEGER GREATER THAN 1 ---" ;; -d) # get delay shift # to get the next parameter - delay # test if parameter starts with minus sign errorMsg="--- INVALID DELAY SPECIFICATION ---" checkMinus "$1" delay=`expr "$1" : '\([0-9]*\)'` [ "$delay" = "" ] && errMsg "DELAY=$delay MUST BE AN INTEGER" delaytest=`echo "$delay < 1" | bc` [ $delaytest -eq 1 ] && errMsg "--- DELAY=$delay MUST BE A POSITIVE INTEGER ---" ;; -p) # get pause shift # to get the next parameter - pause # test if parameter starts with minus sign errorMsg="--- INVALID PAUSE SPECIFICATION ---" checkMinus "$1" pause=`expr "$1" : '\([0-9]*\)'` [ "$pause" = "" ] && errMsg "PAUSE=$pause MUST BE A NON-NEGATIVE INTEGER" ;; -r) # set frame reversal append reverse="yes" ;; -e) # set exponentiation expo="exponential" ;; -) # 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 infolder1=$1 infolder2=$2 out=$3 fi #!/bin/bash -x if [ $frames = 1 ]; then N1=$(ls $infolder1 | wc -l) N2=$(ls $infolder2 | wc -l) highest_number=0 for x in $N1 $N2 do if [ $x -gt $highest_number ] then highest_number=$x fi done frames=$highest_number else N1=$(ls $infolder1 | wc -l) N2=$(ls $infolder2 | wc -l) fi COUNT=1 COUNT1=1 COUNT2=2 renaming () { VAR=`printf "%03d" $COUNT`.png if [ $COUNT1 -le $N1 ]; then VAR1=$(printf "%03d" $COUNT1).png else VAR1=$(printf "%03d" 1).png COUNT1=1 fi if [ $COUNT2 -le $N2 ]; then VAR2=$(printf "%03d" $COUNT2).png else VAR2=$(printf "%03d" 1).png COUNT2=1 fi } # test that infile1 provided [ "$infolder1" = "" ] && errMsg "NO INPUT FILE 1 SPECIFIED" # test that infile2 provided [ "$infolder1" = "" ] && errMsg "NO INPUT FILE 2 SPECIFIED" # set temporary files tmpA="$dir/transitions_1_$$.mpc" tmpB="$dir/transitions_1_$$.cache" tmpC="$dir/transitions_2_$$.mpc" tmpD="$dir/transitions_2_$$.cache" tmpE="$dir/transitions_3_$$.mpc" tmpF="$dir/transitions_3_$$.cache" tmp0="$dir/transitions_0_$$.gif" trap "rm -f $tmpA $tmpB $tmpC $tmpD $tmpE $tmpF $tmp0; exit 0" 0 trap "rm -f $tmpA $tmpB $tmpC $tmpD $tmpE $tmpF $tmp0; exit 1" 1 2 3 15 w=`convert $1/001.png -format "%w" info:` h=`convert $1/001.png -format "%h" info:` if [ $mask = "gradient" ]; then convert -size "$w"x"$h" gradient: $tmpE elif [ $mask = "radial" ]; then convert -size "$w"x"$h" xc: -fx "xx=i-w/2; yy=j-h/2; rr=hypot(xx,yy); rr/hypot(w/2,h/2)" $tmpE elif [ $mask = "noise" ]; then convert -size "$w"x"$h" xc: +noise Random -virtual-pixel tile -fx intensity -contrast-stretch 0% $tmpE elif [ $mask = "blurred" ]; then convert -size "$w"x"$h" xc: +noise Random -virtual-pixel tile -fx intensity -blur 0x6 \ -contrast-stretch 0% $tmpE elif [ $mask = "blurrier" ]; then convert -size "$w"x"$h" xc: +noise Random -virtual-pixel tile -fx intensity -blur 0x18 \ -contrast-stretch 0% $tmpE elif [ $mask = "plasma" ]; then convert -size "$w"x"$h" plasma:fractal -virtual-pixel tile -fx intensity $tmpE elif [ $mask = "alternating" ]; then convert \( -size 16x"$w" gradient: -rotate 90 \) \( -clone 0 -rotate 180 \) -append miff:- | \ convert -size "$w"x"$h" tile:miff: -flop $tmpE elif [ $mask = "shutters" ]; then convert -size "$w"x16 gradient: miff:- | convert -size "$w"x"$h" tile:miff: $tmpE fi if convert -quiet -regard-warnings "$infolder1/001.png" +repage "$tmpA" then : ' Do Nothing ' else errMsg "--- FILE in $infolder1/001.png DOES NOT EXIST, IS NOT AN ORDINARY FILE, NOT READABLE, HAS ZERO SIZE OR THE FIRST FILE IS NOT NAMED 001.png ---" fi if convert -quiet -regard-warnings "$infolder2/001.png" +repage "$tmpC" then : ' Do Nothing ' else errMsg "--- FILE in $infolder2.png DOES NOT EXIST, IS NOT AN ORDINARY FILE, NOT READABLE, HAS ZERO SIZE OR THE FIRST FILE IS NOT NAMED 001.png ---" fi if [ "$expo" = "exponential" ] then # exponentiate mask so that transition does not show much of second image too early if convert -quiet -regard-warnings "$tmpE" -fx "(10^(u)-1)/9" +repage "$tmpE" then : ' Do Nothing ' else errMsg "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---" fi elif [ "$mask" = "linear" ] then if convert -quiet -regard-warnings "$tmpE" +repage "$tmpE" then : ' Do Nothing ' else errMsg "--- FILE $infile DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---" fi fi # check image sizes w1=$w h1=$h w2=`convert $tmpC -format "%w" info:` h2=`convert $tmpC -format "%h" info:` [ $w1 -ne $w2 -a $h1 -ne $h2 ] && errMsg "--- IMAGE SIZES DO NOT MATCH ---" # test if hdri and if so limit addition to 100% (white) is_hdri=`convert -list configure | \ sed -n 's/^.*--enable-hdri.*$/1/p'` if [[ $is_hdri -eq 1 ]] then min="-evaluate min 100%" else min="" fi echo "" echo "Generating $frames Frames:" echo "" i=1 if [[ $out = *.* ]] || [[ $out = "" ]]; then VAR1=$(printf "%03d" $COUNT1).png convert $infolder1/$VAR1 $tmp0 let COUNT1=COUNT1+1 # change delay of first and last image if [ $pause -gt 0 ]; then while [ $i -le $pause ]; do VAR1=$(printf "%03d" $COUNT1).png convert -delay $delay $tmp0 -page +0+0 $infolder1/$VAR1 -page +0+0 $tmp0 i=`expr $i + 1` let COUNT1=COUNT1+1 done i=1 else frames=`expr $frames - 1` fi if [ "$mode" = "dissolve" ]; then while [ $i -le $frames ]; do renaming aa=`convert xc: -format "%[fx:100*$i/$frames]" info:` convert $infolder1/$VAR1 $infolder2/$VAR2 \( $tmpE -evaluate add $aa% $min \) -composite miff:- |\ convert -delay $delay $tmp0 -page +0+0 - -page +0+0 $tmp0 i=`expr $i + 1` let COUNT1=COUNT1+1 let COUNT2=COUNT2+1 done elif [ "$mode" = "wipe" ]; then while [ $i -le $frames ]; do renaming tt=`convert xc: -format "%[fx:100($frames-$i)/$frames]" info:` convert $infolder1/$VAR1 $infolder2/$VAR2 \( $tmpE -threshold $tt% \) -composite miff:- |\ convert -delay $delay $tmp0 -page +0+0 - -page +0+0 $tmp0 i=`expr $i + 1` let COUNT1=COUNT1+1 let COUNT2=COUNT2+1 done fi if [ $pause -gt 0 ]; then i=1 while [ $i -le $pause ]; do renaming convert -delay $delay $tmp0 -page +0+0 $infolder2/$VAR2 -page +0+0 $tmp0 i=`expr $i + 1` let COUNT2=COUNT2+1 done fi if [ "$reverse" = "yes" ] then echo "" echo "Reversing Animation - Please Wait" convert $tmp0 -coalesce \( -clone -2-1 \) \ -quiet -layers Optimize $tmp0 fi if [ "$out" != "" ] then convert $tmp0 -loop 0 $out else animate $tmp0 fi else if [[ -d $out ]]; then echo "destination directory already exists" exit 1 else mkdir $out fi if [ $pause -gt 0 ]; then while [ $i -le $pause ]; do renaming cp $infolder1/$VAR1 $out/$VAR i=`expr $i + 1` let COUNT=COUNT+1 let COUNT1=COUNT1+1 done i=1 else renaming frames=`expr $frames - 1` cp $infolder1/$VAR1 $out/$VAR let COUNT=COUNT+1 let COUNT1=COUNT1+1 fi if [ "$mode" = "dissolve" ]; then while [ $i -le $frames ]; do renaming aa=`convert xc: -format "%[fx:100*$i/$frames]" info:` convert $infolder1/$VAR1 $infolder2/$VAR2 \( $tmpE -evaluate add $aa% $min \) -composite $out/$VAR i=`expr $i + 1` let COUNT=COUNT+1 let COUNT1=COUNT1+1 let COUNT2=COUNT2+1 done elif [ "$mode" = "wipe" ]; then while [ $i -le $frames ]; do renaming tt=`convert xc: -format "%[fx:100($frames-$i)/$frames]" info:` convert $infolder1/$VAR1 $infolder2/$VAR2 \( $tmpE -threshold $tt% \) -composite $out/$VAR i=`expr $i + 1` let COUNT=COUNT+1 let COUNT1=COUNT1+1 let COUNT2=COUNT2+1 done fi if [ $pause -gt 0 ]; then i=1 while [ $i -le $pause ]; do renaming cp $infolder2/$VAR2 $out/$VAR i=`expr $i + 1` let COUNT=COUNT+1 let COUNT2=COUNT2+1 done fi fi exit 0