美文网首页
音视频入门-19-使用giflib处理GIF图片

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

作者: binglingziyu | 来源:发表于2021-01-11 16:51 被阅读0次

    * 音视频入门文章目录 *

    GIFLIB

    The GIFLIB project

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

    rainbow.gif

    下面,使用 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
    
    decode-gif-to-rgb.jpg

    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。

    gif-rgb-gif.jpg encode-rgb-to-gif.jpg

    代码:
    audio-video-blog-demos

    参考资料:

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

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


    相关文章

      网友评论

          本文标题:音视频入门-19-使用giflib处理GIF图片

          本文链接:https://www.haomeiwen.com/subject/jmvdaktx.html