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

* 音视频入门文章目录 *

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


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容