An animated file sets the A flag in VP8X,
then has one ANIM chunk and a series of ANMF chunks.
ANIM
A 6-byte payload. Required when the A flag is set and ignored when it is not.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 4 | bytes | background colour | In the byte order blue, green, red, alpha. It may fill unused canvas and transparent pixels of the first frame, and it is the colour used by disposal method 1. It may be non-opaque even when the L flag is clear. Viewers may treat it as a hint. |
| 4 | 2 | u16 | loop count | How many times to play the animation; 0 means forever. |
ANMF
A 16-byte header followed by the frame data. It should not appear when the A flag is clear.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 3 | u24 | frame X | The real left offset is this value × 2. |
| 3 | 3 | u24 | frame Y | The real top offset is this value × 2. |
| 6 | 3 | u24 | frame width minus one | 1-based. |
| 9 | 3 | u24 | frame height minus one | 1-based. |
| 12 | 3 | u24 | frame duration | Milliseconds before the next frame. What a duration of 0, and often of 10 or less, does is left to the implementation; many tools apply a GIF-like minimum. |
| 15 | 1 | bits | flags | See below. |
| 16 | chunk size − 16 | chunks | frame data | An optional ALPH subchunk, a VP8 or VP8L bitstream subchunk, then optional unknown chunks. Each subchunk is padded separately. |
| Spec bit | Mask | Name | Values |
|---|---|---|---|
| 0–5 | FC | reserved | Must be 0; readers ignore them. |
| 6 | 02 | B, blending | 0 alpha-blend the frame onto the previous canvas; 1 overwrite the frame’s rectangle without blending. |
| 7 | 01 | D, disposal | 0 leave the canvas as it is; 1 fill the frame’s rectangle with the background colour. |
The rectangle must fit the canvas: frame X × 2 + frame width must be at most the canvas width, and likewise for the height.
Alpha blending
Channels are 8-bit and not premultiplied.
out.A = src.A + dst.A * (1 - src.A / 255)
if out.A == 0:
out.RGB = 0
else:
out.RGB = (src.RGB * src.A + dst.RGB * dst.A * (1 - src.A / 255)) / out.A
Blending should be done in linear light, using the ICC profile when there is one. Without a profile assume sRGB, linearised with a gamma of about 2.2.
Building the canvas
- Create a canvas of the VP8X size, filled with the background colour or a colour the application chooses.
- Read the loop count from ANIM; 0 means forever.
- At the start of each loop, clear the canvas to the background colour.
- For each ANMF frame in order: check it fits; apply the previous frame’s disposal; draw this frame at (2 × frame X, 2 × frame Y) with its blending method; show the canvas for the frame’s duration; remember this frame’s disposal for the next one.
- After the last frame, start the next loop or leave the final canvas on screen.
The specification’s prose describes the loop count as “Loop Count − 1” for values other than zero, while its pseudocode plays the animation Loop Count times. This page follows the pseudocode.