音视频入门-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 之间相互转换.旋转 ...
随机推荐
- Jmeter(三十二) - 从入门到精通 - Jmeter Http协议录制脚本工具-Badboy5(详解教程)
1.简介 这一篇文章,宏哥主要想讲解一下,录制完脚本不是就完事了,我们有时候还需要断言,看结果是否和我们预期的结果一致.这在测试中都是很重要的.用句老话说:只看结果不看过程. 2.录制脚本 想要断言, ...
- cookie的理解
第一:每个特定的域名下最多生成20个cookie IE6或更低版本最多20个cookie IE7和之后的版本最多可以有50个cookie Firefox最多50个cookie chrome和Safar ...
- aspnetcore webapi 解决发布以后每隔一段时间请求变缓慢
项目:netcore webapi 3.1 平台:windows server 2008 r2 服务器:IIS 7.5 项目发布到IIS以后第一次请求特别慢大概7.8秒,然后每隔5分钟请求一次大概2. ...
- 为什么要有 Servlet ,什么是 Servlet 容器,什么是 Web 容器?
本文已收录至 https://github.com/yessimida/yes ,这里有我的所有文章分类汇总,欢迎 star! 以下代码相信大家都很熟悉,大学时学 Java Web 都写过这样的代码. ...
- P5785 [SDOI2012]任务安排
本题解用于本蒟蒻加深算法印象,也欢迎大家阅读 本篇题解将分为四块,一步一步地讲解本题, Part 1: O(n^3) \(n^3\) 算法应该非常的显然,我们设 \(f_{i,j}\) 为到 \(i\ ...
- maven私有仓库搭建(nexus)
搭建是参考博客:https://blog.csdn.net/zn353010922/article/details/79441122 切换到nexus目录的bin下 启动.状态.停止:./nexus ...
- Int,String,Integer,double之间的类型的相互转换
Int整数,String字符串之间的类型的转换 int转成String 结果为: String转成int类型 结果为: double转成String 结果为: String转成double 结果为: ...
- 开源抓包工具PowerSniff(支持lua,c语言作为脚本实时分析)
做这个程序的意图是wireshark插件编写复杂(虽然也支持lua),而轻量级的工具如smartsniff,minisniff不支持插件化数据分析,各种工具用下来或多或少不顺手.以前写的外挂也都是手工 ...
- ⑥SpringCloud 实战:引入gateway组件,开启网关路由功能
这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...
- rman恢复实践
1) Loss of system DATAFILE 2) Loss of non-system DATAFILE 3) Loss of a DATAFILE without Backup 4) Lo ...