The ultimate guide to make your own GIF on GNU/Linux

Intro

There are already a lot of GIF available on the internet but often it's hard to get the one we're looking for or some are bad quality. So here a complete tutorial to see how we can make our own GIF on GNU/Linux.

Install tools

root@host:~# apt install imagemagick ffmpeg

Make a GIF

Extract a video to png files

user@host:~$ ffmpeg -ss 2:14 -t 6 -i /movies/1988.Rambo.III.MULTI.x264.1080p.mkv -vf fps=10,scale=320:-1 $filename%05d.png

Remove unwanted frames

Convert png files to one GIF file

user@host:~$ convert -loop 0 *.png myimage.gif

Enjoy the result

Sylvester Stallone in Rambo III movie putting his red ruban

Remove black bars

Some movies have black bars that you may want to remove.

Extract a video to png files

user@host:~$ ffmpeg -ss 8:26 -t 9 -i /movies/2000.American.Psycho.MULTI.AC3.1080p.x264.mkv -vf fps=10,scale=320:-1 $filename%05d.png

Crop files

user@host:~$ identify 00039.png
00039.png PNG 320x180 320x180+0+0 8-bit sRGB 79528B 0.000u 0:00.000
user@host:~$ convert -crop 320x130+0+25 00039.png +repage Cropped_00039.png
user@host:~$ for i in 000*; do convert -crop 320x130+0+25 "$i" +repage Cropped_"$i"; done

Make your GIF

user@host:~$ convert -loop 0 Cropped*.png myimage.gif

Enjoy the result

Christian Bale in American Psycho movie smiling

Add text to your GIF

Extract a video to png files

user@host:~$ ffmpeg -ss 19:24 -t 5 -i /movies/1998.The.Big.Lebowski.MULTI.1080p.Bluray.x264.mkv -vf fps=10,scale=320:-1 $filename%05d.png

Add text to a frame

user@host:~$ convert 00016.png -font Cantarell-Extra-Bold -gravity south -pointsize 30 -stroke black -fill white -strokewidth 1 -annotate +0+0 'YOU'\''RE\nAN ASSHOLE!!!' Text_00016.png
Jeff Bridges in The Big Lebowski movie, you're an asshole!

Add text to multiple frames

user@host:~$ for i in 000*; do cp "$i" Text_"$i"; done
user@host:~$ for i in 0001[6-9]*; do convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize 30 -stroke black -fill white -strokewidth 1 -annotate +0+0 'YOU'\''RE\nAN ASSHOLE!!!' Text_"$i"; done
user@host:~$ for i in 0002[0-7]*; do convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize 30 -stroke black -fill white -strokewidth 1 -annotate +0+0 'YOU'\''RE\nAN ASSHOLE!!!' Text_"$i"; done

Make your GIF

user@host:~$ convert -loop 0 Text_*.png myimage.gif

Enjoy the result

Jeff Bridges in The Big Lebowski movie, you're an asshole!

Play with text

text motion

We can simulate text motion

Extract a video to png files

user@host:~$ ffmpeg -ss 16:43 -t 1 -i /movies/1993.groundhog.day.MULTI.1080p.bluray.x264.mkv -vf fps=10,scale=320:-1 $filename%05d.png

Add text

user@host:~$ a=-250;for i in 000*; do convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize 35 -stroke black -fill white -strokewidth 1 -annotate -"$a"+0 'I'\''M THINKING...' Texted_${i}; ((a+=60)); echo "$a"; done
a=-250
	for i in 000*
	do 
		convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize 35 -stroke black -fill white -strokewidth 1 -annotate -"$a"+0 'I'\''M THINKING...' Texted_${i}
		a=$((a+60))
		echo "$a"
	done

Make your GIF

user@host:~$ convert -loop 0 Texted_*.png myimage.gif

Enjoy the result

Bill Murray in Groundhog Day movie, I'm thinking

text shaking

We can simulate text shaking

Extract a video to png files

user@host:~$ ffmpeg -ss 45:02 -t 2 -i /movies/1995.ace.ventura.when.nature.calls.MULTI.1080p.x264.ac3.mkv -vf fps=10,scale=320:-1 $filename%05d.png

Add text

user@host:~$ for i in 000*; do posX=$RANDOM;let 'posX %= 5'; posY=$RANDOM;let 'posY %= 15'; convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize 40 -stroke black -fill white -strokewidth 1 -annotate +"$posX"+"$posY" 'WARRRMMM!' Texted_${i}; done
for i in 000*
do
	posX=$RANDOM
	let 'posX %= 5'
	posY=$RANDOM;
	let 'posY %= 15'
	convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize 40 -stroke black -fill white -strokewidth 1 -annotate +"$posX"+"$posY" 'WARRRMMM!' Texted_${i}
done

Make your GIF

user@host:~$ convert -loop 0 Texted_*.png myimage.gif

Enjoy the result

Ace Ventura, Jim Carrey, Warm!!

text zooming

zoom on text

Extract a video to png files

user@host:~$ ffmpeg -ss 4:09 -t 2 -i /movies/1991.Armour.of.God.2.1080p.x264.mkv -vf fps=10,scale=320:-1 $filename%05d.png

Add text

user@host:~$ a=20; for i in 000*; do convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize "$a" -stroke black -fill white -strokewidth 1 -annotate +0+0 'OK!' Texted_${i}; ((a+=3)); done
a=20
for i in 000*
do
	convert "$i" -font Cantarell-Extra-Bold -gravity south -pointsize "$a" -stroke black -fill white -strokewidth 1 -annotate +0+0 'OK!' Texted_${i}
	((a+=3))
done

Make your GIF

user@host:~$ convert -loop 0 Texted_*.png myimage.gif

Enjoy the result

Armour of God II, Jackie Chan, OK!

Reduce GIF size

Depending on where you want to publish your GIF, size could matter. For example if I want to share GIF via MMS and keep source quality, size should be lower than 600KB.

Let's see differents way to reduce our GIF.

With normal parameters

user@host:~$ ffmpeg -ss 17:05 -t 8 -i /movies/1994.Pulp.Fiction.MULTI.mkv -vf fps=10,scale=320:-1 $filename%05d.png
user@host:~$ convert -loop 0 00* myimage.gif
user@host:~$ du -sh myimage.gif
2,3M    myimage.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda

Use palettegen

user@host:~$ ffmpeg -y -ss 17:05 -t 8 -i /movies/1994.Pulp.Fiction.MULTI.mkv -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png
user@host:~$ ffmpeg -y -ss 17:05 -t 8 -i /movies/1994.Pulp.Fiction.MULTI.mkv -i palette.png -filter_complex "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
user@host:~$ du -sh output.gif
1,7M    output.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda http://blog.pkh.me/

Compress with fuzz parameter

It will reduce GIF size and output quality. Good compress rate results with limited motions.

user@host:~$ convert myimage.gif -fuzz 2% -layers Optimize result.gif; du -sh result.gif
user@host:~$ du -sh result.gif
1,5M    result.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda
user@host:~$ convert myimage.gif -fuzz 5% -layers Optimize result.gif
user@host:~$ du -sh result.gif
720K    result.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda

Fuzz + palettegen

user@host:~$ ffmpeg -y -ss 17:05 -t 8 -i /movies/1994.Pulp.Fiction.MULTI.mkv -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png
user@host:~$ ffmpeg -y -ss 17:05 -t 8 -i /movies/1994.Pulp.Fiction.MULTI.mkv -i palette.png -filter_complex "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" out%05d.png
user@host:~$ convert -loop 0 out000* myimage.gif; du -sh myimage.gif
user@host:~$ convert myimage.gif -fuzz 2% -layers Optimize result.gif; du -sh result.gif
1,1M    result.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda
user@host:~$ convert myimage.gif -fuzz 5% -layers Optimize result.gif; du -sh result.gif
536K    result.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda

Reducing scale

We could also scale down our GIF

user@host:~$ for i in 00*; do convert "$i" -resize 240x Scalled_$i; done
user@host:~$ convert -loop 0 Scalled_000* myimage.gif; du -sh myimage.gif
1,3M	myimage.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda

Drop frames + Fuzz

user@host:~$ ffmpeg -y -ss 17:05 -t 8 -i /movies/1994.Pulp.Fiction.MULTI.mkv -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png
user@host:~$ ffmpeg -y -ss 17:05 -t 8 -i /movies/1994.Pulp.Fiction.MULTI.mkv -i palette.png -filter_complex "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" out%05d.png
user@host:~$ convert -delay 22 -loop 0 $(ls out000* | grep -E "*[02468].png") myimage.gif; du -sh myimage.gif
1,1M	myimage.gif
user@host:~$ convert myimage.gif -fuzz 5% -layers Optimize result.gif; du -sh result.gif
340K	result.gif
Samuel L. Jackson in Pulp Fiction movie, drinking soda
Licence Creative Commons
This website http://shebangthedolphins.net is licensed to the public under a licence Creative Commons Attribution licence.
Contact :