音视频入门-19-使用giflib处理GIF图片
GIFLIB
上一篇 【手动生成一张GIF图片】, 自己生成了一张 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

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。


参考资料:
How do I get the RGB colour data from a GIFLIB SavedImage structure
音视频入门-19-使用giflib处理GIF图片的更多相关文章
- 音视频入门-20-BMP、PNG、JPG、GIF静态图生成GIF动态图
* 音视频入门文章目录 * 静态图 -> 动态图 前面 [18-手动生成一张GIF图片] 和 [19-使用giflib处理GIF图片] 生成的 GIF 每一帧都是一个颜色,平时用到的 GIF 每 ...
- 音视频入门-18-手动生成一张GIF图片
* 音视频入门文章目录 * GIF 编码知识 GIF 包含的数据块: 文件头(Header) 逻辑屏幕标识符(Logical Screen Descriptor) 全局颜色表(Global Color ...
- 堪称教科书级别的Android音视频入门进阶学习手册,开源分享!
概述 随着整个互联网的崛起,数据传递的形式也在不断升级变化,总的流行趋势如下: 纯文本的短信,QQ -> 空间,微博,朋友圈的图片文字结合 -> 微信语音 -> 各大直播软件 -&g ...
- 音视频入门-11-PNG文件格式详解
* 音视频入门文章目录 * PNG 文件格式解析 PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDAT.IEND)组成. PNG 文件包括 8 字节 ...
- 音视频入门-12-手动生成一张PNG图片
* 音视频入门文章目录 * 预热 上一篇 [PNG文件格式详解]详细介绍了 PNG 文件的格式. PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDA ...
- 音视频入门-14-JPEG文件格式详解
* 音视频入门文章目录 * JPEG 文件格式解析 JPEG 文件使用的数据存储方式有多种.最常用的格式称为 JPEG 文件交换格式(JPEG File Interchange Format,JFIF ...
- 音视频入门-13-使用开源库生成PNG图片
* 音视频入门文章目录 * RGB-to-PNG 回顾 上一篇 [手动生成一张PNG图片] 根据 [PNG文件格式详解] 一步一步地手动实现了将 RGB 数据生成了一张 PNG 图片. 有许多开源的 ...
- 音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合
* 音视频入门文章目录 * libyuv libyuv 是 Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转.缩放等的库.它是跨平台的,可在 Windows.Linux.Mac.A ...
- 音视频入门-09-RGB&YUV互转-使用开源库
* 音视频入门文章目录 * 介绍开源库 使用第三方开源库来简化开发,屏蔽一些底层的复杂度,节省大量编写代码的时间. libyuv: Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转 ...
随机推荐
- 第 4 篇 Scrum 冲刺博客
每天举行会议 会议照片: 昨天已完成的工作与今天计划完成的工作及工作中遇到的困难: 成员姓名 昨天完成工作 今天计划完成的工作 工作中遇到的困难 蔡双浩 实现收藏夹功能 实现重设计的个人界面功能 无 ...
- vue优点
低耦合.视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View ...
- linux tar 压缩和解压缩
tar -c: 建立压缩档案-x:解压-t:查看内容-r:向压缩归档文件末尾追加文件-u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个. 下面 ...
- C++异常之三 异常处理接口声明
异常处理接口声明 1 一般为了方便程序员阅读代码,提高程序的可读性,会将函数中的异常类型声明至函数头后方,不用一行一行的找抛出内容: 2 这里要注意一点,这属于C++的标准语法,但在VS中这个操作不被 ...
- 开始学习Django,配置静态登录页面
开始学习Django,配置静态登录页面 准备阶段 众所周知,Django是一个重量级的设备齐全的web开发框架.在学习Django前我们需要具备如下的知识点: python基础编程 并发 网络编程 H ...
- curl使用技巧汇总
1,curl 忽略证书安全验证 curl https://192.168.1.5:8443-insecure -I
- IDEA中flink程序报错找不到类
Idea中运行flink程序,报错找不到类,其中pom文件中一项依赖为: <dependency> <groupId>org.apache.flink</groupId& ...
- Spark Connector Reader 原理与实践
本文主要讲述如何利用 Spark Connector 进行 Nebula Graph 数据的读取. Spark Connector 简介 Spark Connector 是一个 Spark 的数据连接 ...
- ES6中的Promise和Generator详解
目录 简介 Promise 什么是Promise Promise的特点 Promise的优点 Promise的缺点 Promise的用法 Promise的执行顺序 Promise.prototype. ...
- 多任务-python实现-继承Thread类,单独编写一个类(2.1.2)
@ 目录 1.thread类 1.thread类 threding代码实现 import threading import time class MyThread(threading.Thread): ...