Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gdImageGifAnimAdd fails to add frame when previous frame was the same #971

@JakeOShannessy

Description

@JakeOShannessy

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;
}

Image

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.

Image

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 previm parameter, 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions