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 may 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. If the encoder were truly dropping data, that log line shouldn’t exist.
- 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 didn’t disappear. They were legally merged. 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.