In order to demonstrate some new features / issues etc. it's sometimes quite handy to use short screen captures. The only problem is that they are most of the times too large to share easily or it's just not possible to seamlessly add them to GitHub issues - but what other cool way is there to get your point across? ;)
For the lazy ones: the
video2gif.shscript can be found as a Gist.
Of course there are plenty of apps for all system to do this conversion for you but as a developer I don't want an extra app for every little task at hand and a plain bash script works like a charm - also on macOS/OS X.
Requirements for my ideal Script
There are a few key points I want my ideal video to GIF conversion script to support:
- Scaling - while converting immediately scale down the video to another size
- FPS - specify the frame rate of the GIF (to be able to make them really smooth)
- Trim the end - while converting leave out some seconds at the end (used during automation later)
Existing Scripts and Commands
I started some research and found some existing solutions like this Gist or in this question on StackOverflow. Both of them make use of
ffmpeg for the initial video conversion but either revert back to the usage of
gifsicle for GIF file creation. Trying these out I got some serious quality errors and problems, especially when using
gifsicle. One of the examples from the Gist above is:
ffmpeg -i in.mov -s 600x400 -pix_fmt rgb24 -r 10 -f gif - | gifsicle --optimize=3 --delay=3 > out.gif
However, this command at least includes two of the major requirements I had for my script: allow scaling of the output (
-s 600x400) and specifying the target frame rate (
After some extensive research and trying out various commands the best solutions for me where produced by first generating a color palette from the video material and then do the conversion using a complex filter (
-lavfi). The basic filter I use is as follows:
Here I can substitute
$FPS with my designated frame rate and include the
$SCALE as a scale down factor, i.e.
SCALE = 2 will result in a GIF with half the size of the video (
ih match the input file's width and height respectively).
Generating the palette file can be done with the command:
ffmpeg -i $FULLPATH -vf "$FILTERS,palettegen" -y $PALETTE
$FULLPATH is the path to the input file and
$FILTERS are the filters from above. This will generate a PNG file stored as
$PALETTE. The palette is subsequently used as input besides the original movie file. The final conversion step is executed with:
ffmpeg -i $FULLPATH -i $PALETTE -lavfi "$FILTERS [x]; [x][1:v] paletteuse" -y $GIF
Using the filters and palette constructed above this will result in a very nice quality GIF file like the example below (created on a Retina Mac, 10 fps, scale 2).
The only thing missing: trimming the end. In the example above you can see the
-c|--cutoff option in the help message. Luckily,
ffprobe which comes with
ffmpeg allows us to get time information from a video file. Executing the following command gives us the duration of the video in seconds:
ffprobe -loglevel quiet -of compact=p=0:nk=1 -show_entries format=duration -i $FULLPATH
Last we take the cutoff at the end, subtract it from the duration and get our final video length to process (where
$DURATION is the length in seconds):
DURATION_DIFF=$(echo "$DURATION - $CUTOFF" | bc -l)
By specifying the
-t $DURATION_DIFF parameter to our conversion commands from above we can also include the trim operation as we like directly into the processing.
The final script is available here.
As a final step I wanted to facilitate the creation of GIFs out of screen captures on my Mac even further - including the step of creating screen captures. Thus, I wrote myself a custom workflow for Alfred.
The workflow allows me to easily start a screen capture by typing the short command
scr to start the capture.
Once finished, I use Alfred to stop the capture and convert it to a GIF file using the script from above all in one step:
Of course the workflow also supports saving the capture as a plain
I hope my script is useful for some of you - if you have any suggestions for improvements just leave a comment here or on the Gist! Also feel free to use my Alfred workflow if you like to :)