libvips Stores an Animation as One Tall Stacked Strip
libvips stores a multi-frame image not as N frames but as one tall page-strip — every frame stacked vertically, with page-height, n-pages, and delay in metadata.
When libvips handles any multi-frame image (animated GIF or WebP, multi-page TIFF or PDF), it doesn’t store N separate frames. It stacks every frame vertically into one tall image, officially a page-strip. I picture an unrolled toilet roll.
- The structure lives in metadata:
page-height(one frame’s height),n-pages(frame count),delay(ms per frame). The invariant isn-pages × page-height = total height. - So
imageRef.Height()returns the strip height (every frame combined), andPages() > 1is the flag that you’re holding a strip, not a still.
I originally guessed these frames were different sizes. The opposite is true: every frame is identical in size, which is exactly why libvips can stack them neatly. To detect an animation, I just check Pages() > 1.
Frame order in the strip
Frames stack top-down in playback order: frame 0 at the top (y = 0), each next frame directly below. Unrolling the toilet roll top to bottom gives you frames 0 through 4, not the reverse.
top = i × page-height — that's how you crop one out.To extract frame i, crop at y = i × page-height: frame 0 at y=0, frame 4 at y=4·ph. That also proves it’s top-down, not bottom-up.
To libvips, an animation is one tall image, not a pile of frames.
References:
Related: This is what makes one load path for stills and animation and uniform vs positional transforms on a stitched strip work — or go back to the crop, resize, fill overview.