Take the 2-minute tour ×
Graphic Design Stack Exchange is a question and answer site for professional graphic designers and non-designers trying to do their own graphic design. It's 100% free, no registration required.

I have a folder full of videos that I want to convert to an animated gifs. ffmpeg/avconv does a bad job of doing it directly, so I instead convert the video to a gif by first outputting each frame as a png and then converting back to gif using imagemagick. The problem is that this results in a large gif in terms of file size. To solve this I want to "drop" every second or nth frame from the gif, either by skipping every image file when converting to a gif or by removing frames from a gif. How can I do this on Ubuntu (13.04) using imagemagick or some other command-line utility?

share|improve this question
add comment

3 Answers

up vote 6 down vote accepted

Using a bash script

To do this from the command line, you could use a utility called Gifsicle. There is no built in method to delete every other frame, so you'll need to get your hands dirty with some scripting.

Here is a quick script I made to do just a single GIF:

#!/bin/bash
# This script will take an animated GIF and delete every other frame
# Accepts two parameters: input file and output file
# Usage: ./<scriptfilename> input.gif output.gif

# Make a copy of the file
cp $1 $2

# Get the number of frames
numframes=`gifsicle $1 -I | grep -P "\d+ images" --only-matching | grep -P "\d+" --only-matching`

# Deletion
let i=0
while [[ $i -lt $numframes  ]]; do
    rem=$(( $i % 2 ))

    if [ $rem -eq 0 ]
    then
        gifsicle $2 --delete "#"$(($i/2)) -o $2 
    fi

    let i=i+1 
done

I tested it out with a simple countdown GIF:

enter image description here

And here is the result after running it through the script:

enter image description here

This script is of course not bulletproof, but it should lead you in the right direction.

share|improve this answer
    
Thanks, that worked great! –  user5182 Sep 2 '13 at 23:38
    
Note that your deletion loop can be simplified to just let i=0; while [[ $i -lt $(($numframes / 2)) ]]; do gifsicle $2 --delete "#$i" -o $2; let i=i+1; done –  Ilmari Karonen Sep 3 '13 at 17:00
    
In fact, you don't need a loop at all: gifsicle "$1" --unoptimize $(seq -f "#%g" 0 2 $numframes) -O2 -o "$2" will do it in one call. –  Ilmari Karonen Sep 3 '13 at 17:12
add comment

NOTE: This answer was posted before there was a command line/open source requirement, but I'm leaving it up as it may help someone else in the future


Using Photoshop

This is not an open source or command line solution, but you can do this with Photoshop:

FileImportVideo Frames to Layers...

Import video

"Limit To Every __ Frames" will do the trick for you

share|improve this answer
add comment

Here's a simpler solution using gifsicle than JohnB's script:

gifsicle input.gif `seq -f "#%g" 0 2 99` --unoptimize -O2 -o output.gif

This command should work in most Unix shells; I've tested it in bash. Replace input.gif and output.gif with the input and output file names, and 99 with the number of frames in your animation. (It's OK to use a larger number, but gifsicle will complain about it.)

Some notes:

  • The --unoptimize switch will merge frames in the input animation with the preceding ones, so that each frames stands alone and doesn't depend in any others. You really want to do this before doing pretty much anything with animations, otherwise you're likely to get messy results. (If your input animation is already unoptimized, gifsicle may print a warning about it, but this is also completely harmless.)

  • Conversely, the -O2 switch re-optimizes the output animation to minimize the file size. With JohnB's sample animation, it shrinks the output size down by 27%.

  • The seq command just outputs a sequence of numbers from 0 to 99, counting up in steps of 2. The -f "#%g" makes it print a # before each number, which makes gifsicle understand it as a frame selection instead of a file name. The backticks (`) around the seq command cause its output to be included as parameters in the gifsicle command line.

share|improve this answer
    
Nicely done! If you really wanted, you could use the grep from my script to accurately give the number of frames (and make one behemoth of a command). Or perhaps there is a simpler way to return the number of frames in an animated GIF? –  JohnB Sep 3 '13 at 17:33
2  
I ended up making a behemoth of a command, @JohnB - gifsicle input.gif `seq -f "#%g" 0 2 $(identify input.gif | tail -1 | cut -d "[" -f2 - | cut -d "]" -f1 -)` --unoptimize -O2 -o output.gif –  Kasra Rahjerdi Jan 22 at 5:18
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.