* 音视频入门文章目录 *

GIFLIB

The GIFLIB project

上一篇 【手动生成一张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。


代码:

audio-video-blog-demos

参考资料:

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

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


音视频入门-19-使用giflib处理GIF图片的更多相关文章

  1. 音视频入门-20-BMP、PNG、JPG、GIF静态图生成GIF动态图

    * 音视频入门文章目录 * 静态图 -> 动态图 前面 [18-手动生成一张GIF图片] 和 [19-使用giflib处理GIF图片] 生成的 GIF 每一帧都是一个颜色,平时用到的 GIF 每 ...

  2. 音视频入门-18-手动生成一张GIF图片

    * 音视频入门文章目录 * GIF 编码知识 GIF 包含的数据块: 文件头(Header) 逻辑屏幕标识符(Logical Screen Descriptor) 全局颜色表(Global Color ...

  3. 堪称教科书级别的Android音视频入门进阶学习手册,开源分享!

    概述 随着整个互联网的崛起,数据传递的形式也在不断升级变化,总的流行趋势如下: 纯文本的短信,QQ -> 空间,微博,朋友圈的图片文字结合 -> 微信语音 -> 各大直播软件 -&g ...

  4. 音视频入门-11-PNG文件格式详解

    * 音视频入门文章目录 * PNG 文件格式解析 PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDAT.IEND)组成. PNG 文件包括 8 字节 ...

  5. 音视频入门-12-手动生成一张PNG图片

    * 音视频入门文章目录 * 预热 上一篇 [PNG文件格式详解]详细介绍了 PNG 文件的格式. PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDA ...

  6. 音视频入门-14-JPEG文件格式详解

    * 音视频入门文章目录 * JPEG 文件格式解析 JPEG 文件使用的数据存储方式有多种.最常用的格式称为 JPEG 文件交换格式(JPEG File Interchange Format,JFIF ...

  7. 音视频入门-13-使用开源库生成PNG图片

    * 音视频入门文章目录 * RGB-to-PNG 回顾 上一篇 [手动生成一张PNG图片] 根据 [PNG文件格式详解] 一步一步地手动实现了将 RGB 数据生成了一张 PNG 图片. 有许多开源的 ...

  8. 音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合

    * 音视频入门文章目录 * libyuv libyuv 是 Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转.缩放等的库.它是跨平台的,可在 Windows.Linux.Mac.A ...

  9. 音视频入门-09-RGB&YUV互转-使用开源库

    * 音视频入门文章目录 * 介绍开源库 使用第三方开源库来简化开发,屏蔽一些底层的复杂度,节省大量编写代码的时间. libyuv: Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转 ...

随机推荐

  1. XSS挑战赛(4)

    16-20关 第十六关 关键代码为: <?php ini_set("display_errors", 0); $str = strtolower($_GET["ke ...

  2. Alpha冲刺——序言篇(任务与计划)

    Alpha冲刺--序言篇(任务与计划) 1.整个项目预期的任务量 需求规格说明书 架构设计,原型设计,原型改进(给目标用户展现原型,并进一步理解需求) 编码规范完成.平台环境搭建完成.初步架构搭建 队 ...

  3. 百度前端技术学院-基础-day5.6

    今天学习了关于盒模型.浮动等页面布局的方法. 受到同学的启发,顺便学习了flex的布局. 还了解了一些编码的基本规则. 对我接下来的学习帮助很大. 交作业: HTML : https://github ...

  4. jsonp使用post方法

    来源https://www.jb51.net/article/68980.htm

  5. Java并发编程的艺术(四)——JMM、重排序、happens-before

    什么是JMM JMM就是Java内存模型.目的是为了屏蔽系统和硬件的差异,让同一代码在不同平台下能够达到相同的访问结果.规定了线程和内存之间的关系. 内存划分 JMM规定了内存主要划分为主内存和工作内 ...

  6. js获取url参数、图片转本地base64跨域问题

    获取url参数是经常需要用的一个方法,url上的参数可以让我们的程序执行更灵活. 图片转本地也是很实用的,因为海报合成通常只支持本地. 下面我们来看看这些功能的实现: 获取所有参数,采用split拆分 ...

  7. Python使用requests发送请求

    Python使用第三方包requests发送请求,实现接口自动化 发送请求分三步: 1.组装请求:包括请求地址.请求头header.cookies.请求数据等 2.发送请求,获取响应:支持get.po ...

  8. IntelliJ IDEA(十二) :IDEA常用配置

    idea版本 2019.3.4 配置JDK File--> Project Structure... 修改项目 jdk和项目语言等级 修改jdk版本 File--> Ohter Setti ...

  9. day112:MoFang:种植园使用websocket代替http&服务端基于flask-socketio提供服务&服务端响应信息&种植园页面显示初始化

    目录 1.种植园使用websocket代替http 2.服务端基于socket提供服务 3.服务端响应信息 4.种植园页面展示 1.种植园使用websocket代替http 我们需要完成的种植园,是一 ...

  10. jmeter性能测试-高并发分布式部署

    jmeter什么要做分布式部署? jmeter是运行在JVM虚拟机上的,当模拟大量并发时,对运行机器的性能/网络负载会很大. 此时就需要使用jmeter的分布式部署功能,实现多台被控机器同时并发访问被 ...