3

音视频入门-19-使用giflib处理GIF图片

 3 years ago
source link: https://segmentfault.com/a/1190000038934045
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

音视频入门文章目录

GIFLIB

The GIFLIB project

上一篇 【手动生成一张GIF图片】 , 自己生成了一张 GIF 动态图 rainbow.gif

nQZFnu3.gif!mobile

下面,使用 GIFLIB 分离出 GIF 每一帧的 RGB ,然后将分离出的 RGB 再合成 GIF。

GIF to RGB

GIFLIB 项目里的 gif2rgb.c 已经实现了解码 GIF -> RGB。不过 gif2rgb.c 只保存了最后一帧图片的 RGB,这里需要改造。

gif2rgb.c

gif2rgb.c 在 GIF2RGB 方法最后才调用 DumpScreen2RGB 保存 RGB。

......

static void DumpScreen2RGB(char *FileName,
                           ColorMapObject *ColorMap,
                           GifRowType *ScreenBuffer,
                           int ScreenWidth, int ScreenHeight)
{
......
}

static void GIF2RGB(int NumFiles, char *FileName, 
            bool OneFileFlag, 
            char *OutFileName)
{
    ......
    
    /* Scan the content of the GIF file and load the image(s) in: */
    do {
    ......
    } while (RecordType != TERMINATE_RECORD_TYPE);
    
    /* Lets dump it - set the global variables required and do it: */
    ColorMap = (GifFile->Image.ColorMap
        ? GifFile->Image.ColorMap
        : GifFile->SColorMap);
    if (ColorMap == NULL) {
        fprintf(stderr, "Gif Image does not have a colormap\n");
        exit(EXIT_FAILURE);
    }

    /* check that the background color isn't garbage (SF bug #87) */
    if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) {
        fprintf(stderr, "Background color out of range for colormap\n");
        exit(EXIT_FAILURE);
    }

    DumpScreen2RGB(OutFileName, OneFileFlag,
           ColorMap,
           ScreenBuffer, 
           GifFile->SWidth, GifFile->SHeight);

    (void)free(ScreenBuffer);

    if (DGifCloseFile(GifFile, &Error) == GIF_ERROR) {
    PrintGifError(Error);
    exit(EXIT_FAILURE);
    }

}

gif-to-rgb-library.c

需要把调用 DumpScreen2RGB 的位置移到循环体内 case IMAGE_DESC_RECORD_TYPE: 位置。

......

static void DumpScreen2RGB(char *FileName,
                           ColorMapObject *ColorMap,
                           GifRowType *ScreenBuffer,
                           int ScreenWidth, int ScreenHeight)
{
......
}

static void GIF2RGB( char *FileName, char *OutFileNamePattern)
{
    ......
    do {
        ......
        switch (RecordType) {
            case IMAGE_DESC_RECORD_TYPE:
                ......

                ColorMap = (GifFile->Image.ColorMap
                            ? GifFile->Image.ColorMap
                            : GifFile->SColorMap);
                if (ColorMap == NULL) {
                    fprintf(stderr, "Gif Image does not have a colormap\n");
                    exit(EXIT_FAILURE);
                }

                /* check that the background color isn't garbage (SF bug #87) */
                if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) {
                    fprintf(stderr, "Background color out of range for colormap\n");
                    exit(EXIT_FAILURE);
                }

                char *name = malloc(255*sizeof(char));
                sprintf(name, OutFileNamePattern,  screenIndex++);
                printf("Final File Name: %s\n", name);

                DumpScreen2RGB(name,
                               ColorMap,
                               ScreenBuffer,
                               GifFile->SWidth, GifFile->SHeight);
                break;
            case EXTENSION_RECORD_TYPE:
            ......
        }
    } while (RecordType != TERMINATE_RECORD_TYPE);
   ......
}

int main(int argc, char **argv) {
    GIF2RGB( "/Users/staff/Desktop/rainbow.gif", "/Users/staff/Desktop/rainbow-%d.rgb");
    return 0;
}

查看 GIF -> RGB 结果

根据 【手动生成一张GIF图片】 生成的 GIF rainbow.gif 含有 7 个图像,所以会得到 7 个 .RGB 文件。

ffplay 查看 RGB 文件:

ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-0.rgb
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-1.rgb
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-2.rgb
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-3.rgb
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-4.rgb
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-5.rgb
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-6.rgb

ERN7Vzr.jpg!mobile

RGB to GIF

上面,从 rainbow.gif 中提取出了 7 个 RGB 文件。

下面,读取这 7 个 RGB 文件,使用 GIFLIB 编码成 GIF 动态图。

// LoadRGB 是 gif2rgb.c 文件中的方法
static void LoadRGB(char *FileName,
                    GifByteType **RedBuffer,
                    GifByteType **GreenBuffer,
                    GifByteType **BlueBuffer,
                    int Width, int Height)
{
   ......
}

// gif2rgb.c 文件中 RGB2GIF 只实现了 RGB to GIF 静态图功能
// 这里做了修改,可以生成动态 GIF
static void RGB2GIF(char **RGBFileNames, int NumOfRGBFile, char *GIFFileName,
                    int ExpNumOfColors, int Width, int Height)
{
    int ColorMapSize;
    GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL, *OutputBuffer = NULL;
    ColorMapObject *OutputColorMap = NULL;

    // 打开输出的 GIF 文件
    int Error;
    GifFileType *GifFile;
    if ((GifFile = EGifOpenFileName(GIFFileName, false, &Error)) == NULL) {
        PrintGifError(Error);
        exit(EXIT_FAILURE);
    }

    GifFile->SWidth = Width;
    GifFile->SHeight = Height;
    GifFile->SColorResolution = 1;
    GifFile->SBackGroundColor = 0;
    GifFile->SColorMap = NULL;

    for(int i = 0; i < NumOfRGBFile; i++) {
        ColorMapSize = 1 << ExpNumOfColors;
        printf("读取 RGB 文件:%d\n", i);
        LoadRGB(RGBFileNames[i], &RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
        if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL ||
            (OutputBuffer = (GifByteType *) malloc(Width * Height *
                                                   sizeof(GifByteType))) == NULL)
        GIF_EXIT("Failed to allocate memory required, aborted.");

        if (GifQuantizeBuffer(Width, Height, &ColorMapSize,
                              RedBuffer, GreenBuffer, BlueBuffer,
                              OutputBuffer, OutputColorMap->Colors) == GIF_ERROR)
            exit(EXIT_FAILURE);
        free((char *) RedBuffer);
        free((char *) GreenBuffer);
        free((char *) BlueBuffer);

        printf("MakeSavedImage:%d\n", i);
        SavedImage *image = GifMakeSavedImage(GifFile, NULL);

        GifImageDesc *imageDesc = (GifImageDesc *) malloc(sizeof(GifImageDesc));
        imageDesc->Left = 0;
        imageDesc->Top = 0;
        imageDesc->Width = Width;
        imageDesc->Height = Height;
        imageDesc->Interlace = false;
        imageDesc->ColorMap = OutputColorMap;

        image->ImageDesc = *imageDesc;
        image->RasterBits = OutputBuffer;

        GraphicsControlBlock *GCB = (GraphicsControlBlock *) malloc(sizeof(GraphicsControlBlock));
        GCB->DisposalMode = DISPOSAL_UNSPECIFIED;
        GCB->DelayTime = 50;
        GCB->UserInputFlag = false;
        GCB->TransparentColor = NO_TRANSPARENT_COLOR;

        printf("GCBToSaved:%d\n", i);
        EGifGCBToSavedExtension(GCB, GifFile, i);
    }

    printf("输出文件。");
    // 输出文件
    EGifSpew(GifFile);

}

int main(int argc, char **argv) {
    char *rgbFiles[] = {
            "/Users/staff/Desktop/rainbow-0.rgb",
            "/Users/staff/Desktop/rainbow-1.rgb",
            "/Users/staff/Desktop/rainbow-2.rgb",
            "/Users/staff/Desktop/rainbow-3.rgb",
            "/Users/staff/Desktop/rainbow-4.rgb",
            "/Users/staff/Desktop/rainbow-5.rgb",
            "/Users/staff/Desktop/rainbow-6.rgb",
    };

    RGB2GIF(rgbFiles, 7, "/Users/staff/Desktop/rainbow0.gif", 3, 700, 700);
    return 0;
}

查看 RGB -> GIF 结果

成功实现了 GIF -> RGB(s) -> GIF。

jQfMNvI.jpg!mobile

feqIZnf.jpg!mobile

参考资料:

图像解码之三——giflib解码gif图片

How do I get the RGB colour data from a GIFLIB SavedImage structure


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK