* 音视频入门文章目录 *

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. JavaScript:记录一些字符串和数组常用的方法

    字符串: 字符串的方法:注意:都不会改变原来的字符串,返回值为新的字符串.如果(1,2),一般是包含小标1,不包含下标2 str.charAt(i): 取str的第i+1个字符,类似数组的arr[i] ...

  2. STL——容器(Set & multiset)的查找

    1. set.find(elem); //查找elem元素,返回指向elem元素的迭代器. 1 #include <iostream> 2 #include <set> 3 4 ...

  3. 安卓实用工具箱v4.3几百种小功能

    款多功能实用工具箱.提供了从日常.图片.查询.设备.辅助.提取.优惠券.趣味游戏等多方面的功能,操作简单,即点即用,避免您下载超多应用的难题,且应用体积轻巧,界面简洁.已去除广告! 下载地址:http ...

  4. Unity 保存游戏,读取游戏,退出游戏

    1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using System. ...

  5. vue中的样式绑定

    样式绑定 样式绑定有class绑定和style绑定,这里我们分别说说 class绑定 class样式绑定与有两种语法:对象语法(v-bind:class='{active:isActive}').数组 ...

  6. 逆袭故事|从“点点点”到月薪17K,这个女孩子做到啦

    姓:XXX,XX VIP 学员,一名自动化测试工程师!之前在某大型培训机构转行学习软件测试时就是木子老师的学生,她也一直关注木子老师的动态,后来知道木子老师打算开设测试开发高级提升班,等开了班就报名了 ...

  7. 网络编程-python实现-socket(1.1.1)

    @ 目录 1.不同电脑进程之间如何通信 2.什么是socket 3.创建socket 1.不同电脑进程之间如何通信 利用ip地址 协议 端口 标识网络的进程,网络中的进程通信就可以利用这个标志与其他进 ...

  8. Django入门实战一

    前言 Django是高水准的Python编程语言驱动的一个开源模型.视图,控制器风格的Web应用程序框架,它起源于开源社区.使用这种架构,程序员可以方便.快捷地创建高品质.易维护.数据库驱动的应用程序 ...

  9. Python机器学习课程:线性回归算法

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最基本的机器学习算法必须是具有单个变量的线性回归算法.如今,可用的高级机器学习算法,库和技术如此之多 ...

  10. 5分钟看懂系列:Python 线程池原理及实现

    概述 传统多线程方案会使用"即时创建, 即时销毁"的策略.尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数极其频繁,那么服务器 ...