使用 libgd 在 C 中逐帧操作 gif

Manipulating gifs frame by frame in C with libgd

我有一个程序可以用来处理各种图像文件。目前它只适用于静态图像。我想提供对 gif 的支持,我一直在寻找乏味的 documentation 但找不到任何关于如何逐帧操作 gif 的参考。

理想情况下,我希望一次处理一帧 gif,使用我的其他函数处理文件中的每一帧,然后重新打包图像。

如果仔细查看 the source code,您可以很容易地发现使用动画帧时的弱实现。

The code does not lie: when you call gdImageCreateFromGif(FILE *fdFile) or gdImageCreateFromGifPtr (int size, void *data), it calls directly to gdImageCreateFromGifCtx(gdIOCtxPtr fd), so you must read'n'search in that function where is the mess. The documentation has no info about it, because this library is very, very old.

在源代码中(fd06f7f on 22 Jun)第 258 行(gdImageCreateFromGifCtx(gdIOCtxPtr fd)):

for (;;) {
    int top, left;
    int width, height;

    if(!ReadOK(fd, &c, 1)) {
        return 0;
    }

    if (c == ';') { /* GIF terminator */
        goto terminated;
    }

    if(c == '!') { /* Extension */
        if(!ReadOK(fd, &c, 1)) {
            return 0;
        }

        DoExtension(fd, c, &Transparent, &ZeroDataBlock);
        continue;
    }

    if(c != ',') { /* Not a valid start character */
        continue;
    }

    /*1.4//++imageCount; */

    if(!ReadOK(fd, buf, 9)) {
        return 0;
    }

    useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);

    bitPixel = 1 << ((buf[8] & 0x07) + 1);
    left = LM_to_uint(buf[0], buf[1]);
    top = LM_to_uint(buf[2], buf[3]);
    width = LM_to_uint(buf[4], buf[5]);
    height = LM_to_uint(buf[6], buf[7]);

    if(((left + width) > screen_width) || ((top + height) > screen_height)) {
        if(VERBOSE) {
            printf("Frame is not confined to screen dimension.\n");
        }
        return 0;
    }

    if(!(im = gdImageCreate(width, height))) {
        return 0;
    }

    im->interlace = BitSet(buf[8], INTERLACE);
    if(!useGlobalColormap) {
        if(ReadColorMap(fd, bitPixel, localColorMap)) {
            gdImageDestroy(im);
            return 0;
        }

        ReadImage(im, fd, width, height, localColorMap, BitSet(buf[8], INTERLACE), &ZeroDataBlock);
    } else {
        if(!haveGlobalColormap) {
            gdImageDestroy(im);
            return 0;
        }

        ReadImage(im, fd, width, height, ColorMap, BitSet(buf[8], INTERLACE), &ZeroDataBlock);
    }

    if(Transparent != (-1)) {
        gdImageColorTransparent(im, Transparent);
    }

    goto terminated;
}

goto 甚至没有尝试读取另一帧就完成了循环。

那是因为此实现旨在 显式 从 gif 中读取一帧。只有 一个.

我在这个图书馆工作过。也有其他缺陷。 PNG 文件的透明度是 7 位,而不是 8 位(这是我使用它并在以后丢弃它的主要原因之一)。

您可以用 gdImageGifAnimBegin(gdImagePtr im, FILE *outFile, int GlobalCM, int Loops)

打包 animated gifs

[TL;DR]: libgd 在加载时没有多帧选项。它不是为了加载动画 gif。