How to trim animated gif (using imagemagick)?

2019-05-22 11:11发布

问题:

Given an animated gif over a solid background color

I'd like to trim away the padding. Concretely, I'd like to crop the image to the maximum extent of the foreground object over all frames:

I can't seem to find the right combination of -alpha, -background to achieve this with a single convert command. For example, if I issue

convert -dispose 2 input.gif -trim -layers TrimBounds fail.gif

I get random "background" colors for frames whose individual trimmed extents are smaller than the maximum extent over all frames:

I can achieve the correct output with a long string of commands:

convert input.gif -trim -layers TrimBounds out-%03d.miff
mogrify -background "rgb(20%,30%,80%)" -layers flatten out-*.miff
convert out-*.miff output.gif
rm out-*.miff

This is slow, writes a bunch of temporary files, and requires me to know the background color ("rgb(20%,30%,80%)") explicitly.

Is there a simpler way to trim an animated gif?

This related question considers explicit cropping rather than automatic trimming.

回答1:

This is an interesting question. At the moment, I do not see how to improve it so that extra file(s) are not needed. But I will consider it further. But I can clean your code up a bit and make it easier for you and make the output.gif look correct.

bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert oHBWq.gif -trim -layers TrimBounds out-%03d.miff
mogrify -background "$bgcolor" -layers flatten out-*.miff
convert -dispose previous -delay 10 out-*.miff -loop 0 output.gif
rm out-*.miff

This does the same thing as above, but only requires saving 1 multi-frame miff file. The subshell loop processing does similar to your mogrify.

bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
num=`convert oHBWq.gif -format "%n\n" info: | head -n 1`
convert oHBWq.gif -trim -layers TrimBounds tmp.miff
(for ((i=0; i<num; i++)); do
convert tmp.miff[$i] -background "$bgcolor" -layers flatten miff:-
done ) |\
convert -dispose previous -delay 10 - -loop 0 output2.gif
rm tmp.miff

This also works without having to save any temp files, but is has to repeat the -trim -layers trim bounds for each loop iteration.

bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
num=`convert oHBWq.gif -format "%n\n" info: | head -n 1`
echo "num=$num"
(for ((i=0; i<num; i++)); do
convert oHBWq.gif -trim -layers TrimBounds miff:- |\
convert -[$i] -background "$bgcolor" -layers flatten miff:-
done ) |\
convert -dispose previous -delay 10 - -loop 0 output3.gif

This is close but for one frame:

bgcolor=`convert oHBWq.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert -dispose previous -delay 10 oHBWq.gif -trim -layers TrimBounds -background "$bgcolor" -layers optimize -loop 0 output5.gif



回答2:

Finally, this seems to work in ImageMagick with one line to get the background color and one line of processing. No temp files are needed.

bgcolor=`convert input.gif[0] -format "%[pixel:u.p{0,0}]" info:`
convert -dispose previous -delay 10 -background "$bgcolor" input.gif -trim -layers TrimBounds -coalesce -layers optimize -loop 0 output.gif



回答3:

You can accomplish this sort of trimming using IM's "-distort" with a defined viewport.

convert oHBWq.gif -coalesce +repage -background none \
   \( -clone 0--1 -trim -flatten -trim \) \
   -set option:distort:viewport %[fx:u[-1].w]x%[fx:u[-1].h]+%[fx:u[-1].page.x]+%[fx:u[-1].page.y] \
   -delete -1 -distort SRT 0 +repage output.gif

That clones the input frames, trims them individually, and flattens them keeping their original alignment. Then it trims that flattened one again to get rid of the excess transparent background. The result will be the right size and have the correct page offsets for the finished images. You don't have to know the background color.

Now you can easily get those dimensions and offsets into a distort viewport setting and do a no-op distort. Delete the cloned flattened one that was used to get the measurements, "+repage" the rest, and finish with whatever other GIF settings you need.