Recently I had to crop a lot of animated gifs down for a project. This isn't hard to do with ImageMagick…
$ convert in.gif -coalesce -repage 0x0 -crop WxH+X+y +repage out.gif
…but it does require some repetitive typing and mental arithmetic and rather mysterious incantations if you don't grok what all the coalescing and repaging is about. (I don't.) So I put together this bash
script to handle that for me. Didn't Paul Graham say that if your coding is repetitive then the problem isn't your project, it's that you're doing it wrong? Specifically you're operating at the wrong level of abstraction.
Because I found myself repetitively wrangling these ImageMagick commands into shape, I decided it was time to sidestep that problem and make a script to do the drudgery for me. Plus this way I can get things like the aspect ratio before and after the changes computed for me.
#!/bin/bash if [ -z "$1" ]; then echo "usage: gifcrop.sh infile.gif left right [top] [bottom] [suffix]" exit fi echo -e " opening \t ${1}" 1>&2 # There are several ways to extract the name of the file that comes before # '.gif' so we can rename it with a suffix: # BASE=${1%.gif} BASE=$(basename ${1} .gif) #BASE=$(echo ${1} | sed 's/.gif/\1/') # Set the margins to be cropped off (Left, Right, Top, Bottom): L=$2 R=$3 T=${4:-0} #use argv[4] (or 0, if argv[4] is undef or empty) B=${5:-0} #use argv[5] (or 0, if argv[5] is undef or empty) SUFFIX=${6:-crop} #use argv[6] (or "crop", if argv[6] is undef or empty) # Get the original size of the image W0=$(identify ${1} | head -1 | awk '{print $3}' | cut -d 'x' -f 1) H0=$(identify ${1} | head -1 | awk '{print $3}' | cut -d 'x' -f 2) aspectOld=$(printf "%4.3f" $(echo $W0/$H0 | bc -l)) echo -e " current size \t ${W0}x${H0}\t($aspectOld)" 1>&2 # Calculate the new size of the image let "W1 = $W0 - ($L + $R)" let "H1 = $H0 - ($T + $B)" aspectNew=$(printf "%4.3f" $(echo $W1/$H1 | bc -l)) echo -e " new size \t ${W1}x${H1}\t($aspectNew)" 1>&2 NEWNAME=${BASE}${SUFFIX}.gif echo -e " saving to \t ${NEWNAME}" 1>&2 convert ${1} -coalesce -repage 0x0 -crop ${W1}x${H1}+${L}+${T} +repage ${NEWNAME}
Simply save this as something like gifcrop.sh
, and then run it like so:
$ gifcrop.sh coolpic.gif 10 20 30 40 _small
That will take 10 pixels off the left, 20 off the right, 30 from the top and 40 from the bottom. The result gets saved as coolpic_small.gif
. The new version is saved as a second file with a suffixed name instead of over-writing because I found that I had to iterate many times to get the correct dimensions, so I wanted both new and original versions available for comparison.
The final three arguments are optional, since most of the time I found myself adjusting the width but leaving the height alone, and I never encountered a situation in which I needed an alternative suffix besides "crop". So these two commands are identical:
$ gifcrop.sh in.gif 10 20 0 0 crop
$ gifcrop.sh in.gif 10 20
This all depends on the format of the results that ImageMagick gives you from the identify
command, which is used to get the current size of the input image. You may need to adjust these two lines:
W0=$(identify ${1} | head -1 | awk '{print $3}' | cut -d 'x' -f 1)
H0=$(identify ${1} | head -1 | awk '{print $3}' | cut -d 'x' -f 2)
On my machine, identify foo.gif | head -1
gives me this output:
foo.gif[0] GIF 250x286 250x286+0+0 8-bit sRGB 128c 492KB 0.000u 0:00.030
The awk
command isolates the 250x286
part, and the cut
command pulls out the two dimensions from that.
I should probably put in --quiet
or --verbose
options to suppress the output, but honestly I like seeing it as an error/sanity check and adding more optional args would put me in a place where I should really re-write this to take in key/value pairs instead of positionals. As an alternative to a --quiet
option, you can just pipe the output of stderr
to /dev/null
to make it go away if it really bothers you, e.g.:
gifcrop.sh foo.gif 100 100 2> /dev/null
I suppose I can't have a blog post about animated gifs without including at least one animated gif. So here's the most recent use I've had for gifcrop.sh, editing a gif of the "Datasaurus Dozen" for use in the Data Science class I'm teaching.