GIF Encoders Legally Merge Identical Frames
What looked like frame loss was a spec-legal optimization. A conforming GIF encoder may merge consecutive identical frames and fold their delays.
What looked like frame loss was a spec-legal optimization. A conforming animated GIF encoder can drop consecutive identical frames and fold their delays into the survivor. Total duration and rendered output are preserved. Only the frame count drops. Optimization, not corruption.
Note the middle column: the encoder writes every frame either way. The log shows cgifsave: N frames even when the decode reads 1. An encoder that truly drops data does not produce that log line.
- libvips
gifsave/cgifsavedoes this by default:keep_duplicate_frames=FALSE, withinterframe_maxerroras the “close enough to merge” threshold. Setkeep_duplicate_frames=TRUEto force all frames through. - Real animated GIFs have differing frames, so they round-trip N-in/N-out. Only all-identical synthetic inputs collapse.
- Any encode-and-count test assertion must use per-frame-differing fixtures (test input files), or it asserts on output the encoder is free to change.
Your frames did not disappear. The encoder legally merged them. The test input is the problem, not the encoder.
Sources:
- https://www.libvips.org/API/8.17/method.Image.gifsave.html
- https://github.com/libvips/libvips/discussions/3962
Related: Back to the chain reaction overview, or see contaminated test oracles and a test result is FACT only about its input.