Creating beautiful animated GIFs with FFmpeg, ImageMagick and Gifsicle

Tsumugi's cute. I hadn't thought about K-On! for a few years until I saw this1 on someone's Twitter feed recently.

You might have heard the phrase "reaction image". Well, I have felt like pic related at times, and I thought that it might be fun to turn it into an animated GIF.

FFmpeg is smart enough to create a GIF directly from the mp4:

  ~/tsumugi $ ffmpeg -loglevel quiet -i tsumugi.mp4 tsumugi.gif

The result.

But it doesn't look very good! It's very grainy compared to the source. I'm not sure what the reason is, and the FFmpeg developers are probably trying their best, but with a bit of patience and an extra tool we can do better.

Instead, let's use FFmpeg to extract each frame as a PNG and stitch them together ourselves.

  ~/tsumugi $ mkdir extract
  ~/tsumugi $ ffmpeg -loglevel quiet -i tsumugi.mp4 -c:v png extract/tsumugi%02d.png
  ~/tsumugi $ ls extract/
  tsumugi01.png  tsumugi03.png  tsumugi05.png  tsumugi07.png  tsumugi09.png
  tsumugi02.png  tsumugi04.png  tsumugi06.png  tsumugi08.png

Now we have each frame of the animation as a PNG. Let's break it down and see what the arguments mean.

-loglevel quiet stops ffmpeg from barfing in the terminal.

-c is the stream specifier, and v tells FFmpeg to decode the video stream to png, our selected codec.

%02d is a print format specifier. If you've ever used a C-style programming language, this will look familiar. It says to number the files padded with one zero, because while it might make sense to a human, your computer probably won't know that tsumugi11 comes after tsumugi2 for instance. Because it's a short animation, two is all we need.

Now we need to make these into GIFs. ImageMagick is a veritable swiss army knife for this type of thing.

  ~/tsumugi/extract $ for i in mugi*.png; do convert "$i" "${i%.png}.gif"; done
  ~/tsumugi/extract $ ls *.gif
  tsumugi01.gif  tsumugi03.gif  tsumugi05.gif  tsumugi07.gif  tsumugi09.gif
  tsumugi02.gif  tsumugi04.gif  tsumugi06.gif  tsumugi08.gif

Finally, we'll use Gifsicle to bring them together.

  ~/tsumugi/extract $ gifsicle --delay=10 --loop --colors 256 *.gif > ../tsumugi.gif

Without --colors 256 Gifsicle complains about there being too many colors. I guess this is because PNG has a broader palette.

--delay is the time between frames, in hundredths of a second. I picked 10 arbitrarily and ran with it because it looks good to me.

--loop makes the animation repeat after it has reached the last frame.

The finished product.

  1. Well, it was originally an mp4, but I made it a webm because you can't play those in Firefox without using Flash or something. As a side note, the same animation rendered as a webm is only 56K, a shocking 93% smaller! It's unfortunate that you can't use them everywhere.