-
Notifications
You must be signed in to change notification settings - Fork 276
Description
Describe the bug
gdImageGifAnimAdd adds a new frame to an animated GIF that is being produced. One of the parameters (previm) to this function is the previous frame that was written. It is suggested that this is for optimisation.
If the same image is added twice (as two successive frames) using the same image data (whether is it the same or different memory) a warning is given and the second frame is not added.
If previm is set to NULL, this does not occur.
To Reproduce
The below code should produce a 100x100 GIF with four solid-colour frames: red, green, green, blue. If the last argument to gdImageGifAnimAdd is set to NULL this works as expected, but as it is below (based on the documentation example) it produces a GIF with only 3 frames (and a warning).
#include <gd.h>
int main()
{
// Create a 100x100 red image
gdImagePtr redFrame = gdImageCreate(100, 100);
gdImageColorAllocate(redFrame, 255, 0, 0);
// Create a 100x100 green image
gdImagePtr greenFrame1 = gdImageCreate(100, 100);
gdImageColorAllocate(greenFrame1, 0, 255, 0);
// Create a second 100x100 green image
gdImagePtr greenFrame2 = gdImageCreate(100, 100);
gdImageColorAllocate(greenFrame2, 0, 255, 0);
// Create a 100x100 blue image
gdImagePtr blueFrame = gdImageCreate(100, 100);
gdImageColorAllocate(blueFrame, 0, 0, 255);
FILE *fp = fopen("./anim.gif", "wb");
if (fp == NULL)
return 1;
gdImageGifAnimBegin(redFrame, fp, 0, 0);
gdImageGifAnimAdd(redFrame, fp, 1, 0, 0, 100, gdDisposalNone, NULL);
gdImageGifAnimAdd(greenFrame1, fp, 1, 0, 0, 100, gdDisposalNone, redFrame);
gdImageGifAnimAdd(greenFrame2, fp, 1, 0, 0, 100, gdDisposalNone, greenFrame1);
gdImageGifAnimAdd(blueFrame, fp, 1, 0, 0, 100, gdDisposalNone, greenFrame2);
gdImageGifAnimEnd(fp);
fclose(fp);
gdImageDestroy(redFrame);
gdImageDestroy(greenFrame1);
gdImageDestroy(greenFrame2);
gdImageDestroy(blueFrame);
return 0;
}Expected behavior
I would have expected it to add the second green frame (resulting in 4 frames total) or somehow increase the duration of the first green frame as an optimisation. Below is the expected result not using the previm parameter.
Actual results
Only 3 frames are produced and the GIF is 3 seconds long instead of 4.
Environment (please complete the following information):
- OS: Fedora 42
- Version 2.3.3
Additional context
Issue #415 appears similar except that was a segfault. This no longer produces a segfault, but does produce unexpected results.
There are two ways to avoid this:
- Never use the
previmparameter, but this would appear to miss optimisation opportunities when images are not the same. - Check the image data of each frame to determine if they are the same before passing them to GD. This is a lot of extra compute considering that GD does the same check.