TechEarl

How to Inspect an Animated GIF (Frame Count, Size, Delay) From the Command Line

Inspect an animated GIF from the command line: read its dimensions, frame count, loop count, and per-frame delays with gifsicle, count frames and detect whether it animates with ImageMagick, extract the first frame, and total its duration.

Ishan Karunaratne⏱️ 7 min readUpdated
Share thisCopied
Inspect an animated GIF from the command line: dimensions, frame count, loop count, per-frame delays, total duration, and whether it is animated at all, with gifsicle and ImageMagick.

The fastest way to read what is inside an animated GIF (its dimensions, how many frames it has, how it loops, and the delay on each frame) is gifsicle --info:

bash
gifsicle --info in.gif

That one command prints the logical screen size, the loop count, and a per-frame listing with each frame's position, size, transparency, and delay. If you just need the headline numbers, the rest of this page covers the targeted commands: counting frames with ImageMagick, deciding whether a GIF is animated at all, pulling out the first frame as a static image, and adding up the delays to get the total play time.

Both gifsicle and ImageMagick are one install away. On most systems it is sudo apt install gifsicle imagemagick (Debian/Ubuntu) or brew install gifsicle imagemagick (macOS). ImageMagick 7 ships the single magick entry point; the older standalone identify and convert binaries still work if your distro packages version 6, so where I use magick identify below, plain identify is the fallback.

Read everything at once with gifsicle

gifsicle -I (the short form of --info) is the most complete single view. For a small animation it prints something like this:

bash
gifsicle --info in.gif
code
* in.gif 12 images
  logical screen 480x270
  global color table [256]
  loop forever
  + image #0 480x270 transparent 255
    disposal asis delay 0.08s
  + image #1 480x270 transparent 255
    disposal asis delay 0.08s
  ...

The first line gives the frame count (12 images). The logical screen line is the canvas size in pixels. loop forever is the loop count (a finite count shows as a number; see control a GIF's loop count for changing it). Each + image #N block is one frame, with its own size, offset, transparency index, disposal method, and delay in seconds. Frames in a GIF are often smaller than the canvas and positioned with an offset, which is why per-frame sizes can differ from the logical screen.

Count the frames

For a clean frame count, ImageMagick has two reliable approaches. The simplest is to let plain identify print one line per frame and count the lines:

bash
magick identify in.gif | wc -l

identify in.gif lists every frame on its own line (in.gif[0] GIF ..., in.gif[1] GIF ..., and so on), so wc -l gives the frame count directly. The other approach uses the %n escape, but with a catch worth knowing:

bash
magick identify -format "%n\n" in.gif | head -n 1

%n is ImageMagick's "number of images in the sequence" escape (its frame count for a GIF), and ImageMagick evaluates the format string once per frame. A 12-frame GIF therefore prints 12 twelve times, so you take the first line with head -n 1 (or the last with tail -n 1). For a large GIF, add -ping to read only the header and skip decoding every frame: magick identify -ping -format "%n\n" in.gif | head -n 1.

Detect whether a GIF is animated

A GIF is animated when it has more than one frame. That makes the frame count the whole test. In a script:

bash
frames=$(magick identify -format "%n\n" in.gif | head -n 1)
[ "$frames" -gt 1 ] && echo "animated ($frames frames)" || echo "static"

This reads the frame count into a variable and branches on whether it exceeds 1. A single-frame .gif is just a static image with a GIF extension, and this returns static for it. Keep the head -n 1 in place: without it the %n repetition feeds a multi-line string into the numeric comparison and the test fails.

Extract the first frame as a static image

ImageMagick's bracket syntax selects a single frame by index, counting from zero. To save the first frame as a PNG:

bash
magick "in.gif[0]" first.png

The [0] reads only frame 0, so you get one static image rather than a multi-frame export. Quote the filename, because the brackets are shell glob characters and an unquoted in.gif[0] can be mangled by the shell before ImageMagick ever sees it. Any index works the same way: magick "in.gif[5]" frame5.png pulls the sixth frame. This is the standard trick for building a static "poster" image to show before a heavy GIF loads, then swapping in the real animation on interaction.

Total the play time from the delays

The total duration of an animated GIF is the sum of its per-frame delays. gifsicle --info already lists each delay in seconds; to total them without reading by eye, sum the centisecond delays ImageMagick reports per frame:

bash
magick identify -format "%T\n" in.gif | awk '{ s += $1 } END { print s/100 " seconds" }'

%T is the per-frame delay in centiseconds (hundredths of a second), the unit the GIF format itself stores. The awk step adds them up and divides by 100 to get seconds. A 12-frame GIF at 8 centiseconds per frame totals 96 centiseconds, so 0.96 seconds per loop. Note that very small delays are unreliable in practice: most browsers clamp anything below about 2 centiseconds up to a default, so a GIF's measured delay total can run faster than what you actually see on screen.

FAQ

See also

Sources

Authoritative references this article was fact-checked against.

TagsgifsicleImageMagickanimated gifgif framesCLIimage inspectionmagick identify

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts