文章目录

  • 一、GIF基础概念
    • gif---一种压缩的位图图形文件格式
    • gif图片的典型特性---压缩/多帧动画/支持alpha/256色
    • gif与其他典型图形文件bmp、jpeg、png对比
    • libgif---一个广泛使用的C语言实现的gif读写库
  • 二、GIF文件格式
    • 3.1 gif文件头File Header---署名和版本号,6字节,确认文件类型
    • 3.2 gif数据流Data Stream
      • 3.2.1 逻辑屏幕标识符Logical Screen Descriptor---7字节
      • 3.2.2 全局颜色列表Global Color Table---任意字节,取决列表数目
      • 3.2.3 图象标识符Image Descriptor---10字节
      • 3.2.4 局部颜色列表Local Color Table
      • 3.2.5 基于颜色列表的图象数据Table-Based Image Data
      • 3.2.6 (可选)图形控制扩展Graphic Control Extension
      • 3.2.6 (可选)注释扩展Comment Extension
      • 3.2.6 (可选)图形控制扩展Graphic Control Extension
      • 3.2.7 (可选)应用程序扩展Application Extension
    • 3.3 gif文件尾Trailer
  • 三、GIF压缩算法简介(待更新)
  • 四、libgif库使用解码用例
    • 4.1 源码下载与安装
    • 4.2 gif解码到rgb数据的示例用例
  • 五、GIF图片相关工具
    • ScreenToGif---一款很方便的gif录制编辑小工具
  • 参考

一、GIF基础概念

gif—一种压缩的位图图形文件格式

GIF:Graphics Interchange Format,以8位色(即256种颜色)重现真彩色的图像。它实际上是一种压缩文档,采用LZW压缩算法进行编码,有效地减少了图像文件在网络上传输的时间。它是目前万维网广泛应用的网络传输图像格式之一,由Compu Serve公司推出。gif早期由于专利问题,引起部分开放源代码社群发起“Burn all GIFs”的运动抵制使用GIF格式,进而产生PNG文件标准,(当前gif的专利已经过期)PNG文件格式凭着其技术上的优势,已然跻身于网络上第三广泛应用格式。

gif图片的典型特性—压缩/多帧动画/支持alpha/256色

1、优秀的压缩算法使其在一定程度上保证图像质量的同时将体积变得很小;2、可插入多帧,从而实现动画效果。3、可设置透明色以产生对象浮现于背景之上的效果。4、由于采用了8位压缩,最多只能处理256种颜色,故不宜应用于真彩色图片。

gif与其他典型图形文件bmp、jpeg、png对比

bmp常见是非压缩的size最大但是显示简单,主要是最后用作本地存储 和 显示阶段-无需解压, 传输都会选择gif、png和jpeg。jpeg图片的优势是压缩比例大,而且支持每个颜色分量8bit甚至以上存储保证画面色彩还原,它由于存在转换到yuv域并进行下采样420,通过有损压缩算法 能得到比png更高的压缩效率,常见的大图都会选择jpeg而非png。png相对jpeg它的优势是包含alpha通道(可以做半透明效果,而jpeg是不存在的alpha通道),并且常用无损压缩,常见用在一些精细小图标,或者必须带上aplha透明度的图片的使用场景。png设计最初目标是替代gif,gif相对前面几种,它和png一样 带alpha通道并压缩,优势是支持多帧动画,缺点是最大256色用于画面质量要求低的场景,比如各种动态表情包。

libgif—一个广泛使用的C语言实现的gif读写库

giflib是一个使用最广泛的gif图片库,它用C语言实现,效率很高,功能很全;

二、GIF文件格式

GIF是按块划分存储的,包括控制块 Control Block(包含控制参数控制数据块行为)和数据块Data Sub-blocks(8-bit的字符流,大小从0到255个字节,第一个字节标识数据块内容size字节大小)两种。
GIF文件主要由以下几部分组成文件头File Header、GIF数据流GIF Data Stream和文件尾部Trailer三个部分。文件头包含GIF文件署名Signature和版本号Version;GIF数据流由控制标识符、图象块Image Block和其他的一些扩展块组成;文件终结器只有一个值为0x3B的字符(’;’)表示文件结束。
我们用下面来这个图片举例。

3.1 gif文件头File Header—署名和版本号,6字节,确认文件类型

文件头包含:1、GIF文件署名,3字节(就是GIF的ASCII码);2、版本号,3字节(87a-1987/5;89a-1989/7)。

3.2 gif数据流Data Stream

gif数据流由各种类型的块组成,介绍如下,其中部分块是可选的,主要在89a版本上得以支持。

3.2.1 逻辑屏幕标识符Logical Screen Descriptor—7字节

逻辑屏幕标识符:第一个gif数据块,定义了GIF分辨率、颜色深度、背景色以及有无全局颜色列表(Global Color Table)和颜色列表的索引数(Index Count)。


可见此图片,宽高都是0xc8=200;0xF7 有全局颜色表,色深8bit,没有排序,全局颜色列表数量256色;

3.2.2 全局颜色列表Global Color Table—任意字节,取决列表数目

在一张连续动态GIF里,每一帧之间信息差异不大,颜色是被大量重复使用的。全局颜色列表就是把图片中用到的颜色提取出来,组成一个调色盘,这样,在存储真正的图片点阵时,只需要存储每个点在调色盘里的索引值。如果调色盘放在文件头,作为所有帧公用的信息,就是全局调色盘,如果放在每一帧的帧信息中,就是局部调色盘。GIF格式允许两种调色盘同时存在,在没有局部调色盘的情况下,使用公共调色盘来渲染。
全局颜色列表必须紧跟在逻辑屏幕标识符后面,每个颜色列表索引条目由三个字节组成,按R、G、B的顺序排列

第一个点R、G、B各自8bit都是0,表示黑色。

3.2.3 图象标识符Image Descriptor—10字节

一个GIF文件内可以包含多幅图象,一幅图象结束之后紧接着下是一幅图象的标识符,图象标识符以0x2C(’,’)字符开始,定义紧接着它的图象的性质,包括图象相对于逻辑屏幕边界的偏移量、图象大小以及有无局部颜色列表和颜色列表大小。


没有任何x、y方向偏移,0xc8=200宽高都是200,没有局部颜色列表。

3.2.4 局部颜色列表Local Color Table

如果上面的局部颜色列表标志置位的话,则需要在这里(紧跟在图象标识符之后)定义一个局部颜色列表以供紧接着它的图象使用。局部颜色列表的排列方式和全局颜色列表一样。

3.2.5 基于颜色列表的图象数据Table-Based Image Data

图象数据由两部分组成:1、第一个字节表示 LZW编码长度LZW Minimum Code Size;2、后续内容 表示 图象数据Image Data,由一个或几个数据块Data Sub-blocks组成。

3.2.6 (可选)图形控制扩展Graphic Control Extension

89a版本,放在一个图象块(图象标识符)或文本扩展块的前面,用来控制跟在它后面的第一个图象(或文本)的渲染(Render)形式。

3.2.6 (可选)注释扩展Comment Extension

89a版本,可以用来记录图形、版权、描述等任何的非图形和控制的纯文本数据(7-bit ASCII字符),注释扩展并不影响对图象数据流的处理,解码器可以忽略。推荐放在数据流的开始或结尾。

3.2.6 (可选)图形控制扩展Graphic Control Extension

89a版本,用来绘制一个简单的文本图象,这一部分由用来绘制的纯文本数据(7-bit ASCII字符)和控制绘制的参数等组成。

3.2.7 (可选)应用程序扩展Application Extension

89a版本,应用程序可以在这里定义自己的标识、信息等,组成。

3.3 gif文件尾Trailer

这一部分0x3B的字符(’;’),块大小0字节,表示文件结束。

三、GIF压缩算法简介(待更新)

四、libgif库使用解码用例

4.1 源码下载与安装

1、源码下载:https://sourceforge.net/projects/giflib/;我下载的最新giflib-5.2.1版本。
2、源码编译安装:阅读源码包build.adoc确认安装流程:make check;make install;
install结果如下,关键部分:1、静态库到/ibgif.a和动态库libgif.so 2、安装了mannul手册 3、安装如gif2rgb等工具

make check
make install
// 部分打印略
install gif2rgb gifbuild giffix giftext giftool gifclrmp "/usr/local/bin"
install -d "/usr/local/include"
install -m 644 gif_lib.h "/usr/local/include"
install -d "/usr/local/lib"
install -m 644 libgif.a "/usr/local/lib/libgif.a"
install -m 755 libgif.so "/usr/local/lib/libgif.so.7.2.0"
ln -sf libgif.so.7.2.0 "/usr/local/lib/libgif.so.7"
ln -sf libgif.so.7 "/usr/local/lib/libgif.so"
install -d "/usr/local/share/man/man1"
install -m 644 doc/*.1 "/usr/local/share/man/man1"

4.2 gif解码到rgb数据的示例用例

先通过man giflib 确认库提供的各种功能支持,其中gif2rgb是我们最需要的。但这里我不使用gif2rgb工具,而是参考一下写法,目的是通过库写一个自己的调试简单sample出来。(giflib不像libjpeg和libpng一样有专门的example示例文件,需要自己配合gif_lib.h头文件 和 小工具源码进行简单分析)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "gif_lib.h"void save_rgb_to_file(int file_num, GifFileType *GifFile, ColorMapObject *ColorMap, char *data, int size) {int i, j;char filename[100] = {0};sprintf(filename, "output_rgb_num%d_w%d_h%d" , file_num,GifFile->SWidth, GifFile->SHeight);FILE *outfile = fopen(filename, "w+");if (outfile == NULL) {printf("out file open failed!\n");return;}unsigned char *Buffer, *BufferP;// 申请一行内存,由于是RGB888,因此每个像素3字节if ((Buffer = (unsigned char *) malloc(GifFile->SWidth * 3)) == NULL) {printf("malloc failed\n");return;}for (i = 0; i < GifFile->SHeight; i++) {char *GifRow = data + i * GifFile->SWidth * sizeof(GifPixelType); // 取每行地址for (j = 0, BufferP = Buffer; j < GifFile->SWidth; j++) { // 遍历每一行每个点GifColorType *ColorMapEntry = &ColorMap->Colors[GifRow[j]];*BufferP++ = ColorMapEntry->Red;*BufferP++ = ColorMapEntry->Green;*BufferP++ = ColorMapEntry->Blue;}if (fwrite(Buffer, GifFile->SWidth * 3, 1, outfile) != 1) { // 写入一行RGB数据printf("fwrite failed!\n");return;           }}free((char *) Buffer);fclose(outfile);return;
}
#define TEST {printf("----%s %d\n", __FUNCTION__, __LINE__);}int main(int argc, char *argv[]) {if (argc < 2) {printf("please intput like: ./a.out xxx.gif\n");return -1;}int i, j, Size, Row, Col, Width, Height, ExtCode, Count;GifRecordType RecordType = UNDEFINED_RECORD_TYPE;GifByteType *Extension = NULL;;GifRowType *ScreenBuffer = NULL;;GifFileType *GifFile = NULL;int InterlacedOffset[] = { 0, 4, 2, 1 }; /* The way Interlaced image should. */int InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */int ImageNum = 0;ColorMapObject *ColorMap;int Error;char *outbuf = NULL;// 打开输入文件if ((GifFile = DGifOpenFileName(argv[1], &Error)) == NULL) {printf("out file open failed!\n");return -1;} if (GifFile->SHeight == 0 || GifFile->SWidth == 0) {printf("resolution error!\n");return -1;}   // 申请输出内存指针数组(类似png解析,每行一个指针)if ((ScreenBuffer = (GifRowType *)malloc(GifFile->SHeight * sizeof(GifRowType))) == NULL) {printf("malloc failed!\n");return -1;      }// 申请输出的整块buffer,并初始化指针数组Size = GifFile->SHeight * GifFile->SWidth * sizeof(GifPixelType);printf("size %d sw %d sh%d!\n", Size, GifFile->SWidth, GifFile->SHeight);if ((outbuf = (char *)malloc(Size)) == NULL){printf("malloc row failed!\n");return -1;               }for (i = 0; i < GifFile->SHeight; i++) {ScreenBuffer[i] = (GifRowType)(outbuf + i * GifFile->SWidth * sizeof(GifPixelType));if (i == 0) {for (j = 0; j < GifFile->SWidth; j++) // 设置第一行背景色ScreenBuffer[0][j] = GifFile->SBackGroundColor; } else { // 他行的内存,复制第一行内容,均为背景色memcpy(ScreenBuffer[i], ScreenBuffer[0], GifFile->SWidth * sizeof(GifPixelType));           }}// 开始遍历文件do {if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {printf("DGifGetRecordType failed!\n");return -1;}switch (RecordType) {case IMAGE_DESC_RECORD_TYPE:if (DGifGetImageDesc(GifFile) == GIF_ERROR) {printf("DGifGetImageDesc failed!\n");return -1;}Row = GifFile->Image.Top; /* Image Position relative to Screen. */Col = GifFile->Image.Left;Width = GifFile->Image.Width;Height = GifFile->Image.Height;printf("buf %p Image %d at (%d, %d) [%dx%d]\n", outbuf, ++ImageNum, Col, Row, Width, Height);// 存文件内容到outbufif (GifFile->Image.Interlace) {/* 交叉型数据 Need to perform 4 passes on the images: */for (Count = i = 0; i < 4; i++)for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {if (DGifGetLine(GifFile, &ScreenBuffer[j][Col], Width) == GIF_ERROR) {printf("DGifGetLine failed!\n");return -1;}}} else {for (i = 0; i < Height; i++) {if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col], Width) == GIF_ERROR) {printf("DGifGetLine failed!\n");return -1;}}}ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);// outbuf存到输出文件save_rgb_to_file(ImageNum, GifFile, ColorMap, outbuf, Size);break;case EXTENSION_RECORD_TYPE:/* Skip any extension blocks in file: */if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {printf("DGifGetExtension failed!\n");return -1;}while (Extension != NULL) {if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {printf("DGifGetExtensionNext failed!\n");return -1;}}break;case TERMINATE_RECORD_TYPE:break;default: /* Should be trapped by DGifGetRecordType. */break;}} while (RecordType != TERMINATE_RECORD_TYPE);// 释放内存free(ScreenBuffer);free(outbuf);// 关闭全部文件DGifCloseFile(GifFile, &Error);return 0;
}

编译与执行

gcc sample_gif.c -lgif
./a.out ./200px-Rotating_earth_large.gif
## 执行打印如下
buf 0xed0620 Image 1 at (0, 0) [200x200]
buf 0xed0620 Image 2 at (29, 15) [141x141]
buf 0xed0620 Image 3 at (28, 15) [142x141]
buf 0xed0620 Image 4 at (28, 15) [142x141]
buf 0xed0620 Image 5 at (29, 15) [141x141]
buf 0xed0620 Image 6 at (29, 15) [141x141]
buf 0xed0620 Image 7 at (29, 15) [141x141]
buf 0xed0620 Image 8 at (30, 15) [139x141]
buf 0xed0620 Image 9 at (29, 15) [140x141]
// 略
buf 0xed0620 Image 44 at (30, 15) [139x141]
## 执行结果如下
root@ubuntu:/home/study/giflib/gif_to_rgb# ls
200px-Rotating_earth_large.gif  output_rgb_num1_w200_h200   output_rgb_num30_w143_h142  output_rgb_num41_w141_h141
a.out                             output_rgb_num20_w140_h141  output_rgb_num31_w143_h142  output_rgb_num42_w141_h141
output_rgb_num10_w140_h141        output_rgb_num21_w142_h141  output_rgb_num32_w141_h141  output_rgb_num43_w140_h141
output_rgb_num11_w140_h141        output_rgb_num22_w142_h141  output_rgb_num33_w141_h141  output_rgb_num44_w139_h141
output_rgb_num12_w141_h141        output_rgb_num23_w141_h141  output_rgb_num34_w140_h141  output_rgb_num4_w142_h141
output_rgb_num13_w142_h141        output_rgb_num24_w140_h141  output_rgb_num35_w140_h141  output_rgb_num5_w141_h141
output_rgb_num14_w142_h141        output_rgb_num25_w140_h141  output_rgb_num36_w141_h141  output_rgb_num6_w141_h141
output_rgb_num15_w141_h141        output_rgb_num26_w140_h141  output_rgb_num37_w141_h141  output_rgb_num7_w141_h141
output_rgb_num16_w140_h141        output_rgb_num27_w140_h141  output_rgb_num38_w141_h141  output_rgb_num8_w139_h141
output_rgb_num17_w139_h141        output_rgb_num28_w141_h141  output_rgb_num39_w142_h142  output_rgb_num9_w140_h141
output_rgb_num18_w140_h141        output_rgb_num29_w142_h141  output_rgb_num3_w142_h141   sample_gif.c

结果查看,用工具随意打开两个图片,如下,说明解码正常:

五、GIF图片相关工具

ScreenToGif—一款很方便的gif录制编辑小工具

ScreenToGIf可以自己录制制作gif文件(点击录制,调整录制窗口,开始录制,录制完成,编辑删除无效帧,另存导出),也可以导入现有gif文件进行编辑或者帧导出;

参考

维基百科:https://chi.jinzhao.wiki/wiki/GIF
格式标准:https://www.w3.org/Graphics/GIF/spec-gif89a.txt
libgif源码:https://sourceforge.net/projects/giflib/
https://blog.csdn.net/wzy198852/article/details/17266507
浅析GIF格式图片的存储和压缩:https://www.cnblogs.com/qcloud1001/p/6647080.html

图形图像基础 之 gif介绍相关推荐

  1. 图形图像基础 之 png介绍

    文章目录 一.png相关概念 png---一种无损压缩算法的位图格式 png和bmp.jpeg图片比较 libpng---一款C语言编写的读写PNG文件的跨平台的库 二.png文件格式---文件标签+ ...

  2. 图形图像基础 之 jpeg介绍

    一.[概念]jpeg相关概念简介 jpeg-一种影像有损压缩标准方法 后缀jpg/jpeg JPEG(Joint Photographic Experts Group 联合图像专家小组)是一种针对照片 ...

  3. 图形图像基础 之 bmp介绍

    文章目录 一.bmp相关概念 位图Bitmap 与 矢量图Vector---用点表示 还是 用公式表示 bmp(Bitmap-File)---一种非压缩图形文件位图格式,后缀bmp 二.bmp文件格式 ...

  4. 4.图形图像素材编辑

    4.图形图像素材编辑 图形.图像是人类视觉所感受到的一种具象化的信息,是多媒体信息的主要类型,也是信息传递最基本.最常见的方式.它可以形象.生动和直观地表达大量的信息,具有文字和声音无可比拟的优点.图 ...

  5. OpenCV图形图像击中击不中HITMISS变换处理基础知识

    ☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 博文传送门: 老猿关于HTM变换的博文目录请见: https://blog.csdn.ne ...

  6. 图形和图像计算机基础知识,计算机图形图像基础

    <计算机图形图像基础>是2011-03-01浙江大学出版社出版的图书,作者是程辉,田少煦.[1] 书    名 计算机图形图像基础 作    者 程辉,田少煦ISBN 9787308083 ...

  7. 一个C#函数学完C#图形图像编程基础

    老师说C#主要用于 1.winform开发 2.网络 3.驱动 在图形图像处理上用的比较少,不过书里有图形图像编程这一章节,为了系统的学完C#编程基础,以及为了能够更熟悉C#的特性,再加上今天晚上闲的 ...

  8. 一步一步学Silverlight 2系列(31):图形图像综合实例—实现水中倒影效果

    Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, Ir ...

  9. c 语言 数据库 pdf下载,Visual C/C++ 编程精选集锦 数据库及图形图像分册 PDF扫描版[38MB]...

    Visual C/C++ 编程精选集锦 数据库及图形图像分册 内容简介: Visual C/C++作为功能强大的可视化应用程序开发工具,是计算机界公认的优秀应用开发工具.Microsoft的基本类库M ...

  10. 视频教程-图形图像-无中生有Photoshop CS6背景素材技法ps教程 [超多案例]-其他

    图形图像-无中生有Photoshop CS6背景素材技法ps教程 [超多案例] 全栈工程师,曾担任多家互联网公司技术总监.运营经理,在技术与运营方面积累了大量实战经验,同时也是清华大学出版社特约作家, ...

最新文章

  1. C# 利用反射调用类下的方法
  2. 谷歌开发专家带你学AI
  3. linux kref详解
  4. 诺顿本月将发布儿童网络安全软件
  5. c++实现任意类型数组类的封装
  6. Django 2.1.3 文档
  7. android activity使用,Android Activity使用拾遗
  8. 持续改进----白狼族的故事(完结)
  9. 全国大学生数学建模竞赛(CUMCM)历年试题(查看超级方便)
  10. excel 如何删除有颜色的行
  11. 支付宝手机网站支付接口集成的经验小结
  12. 打爆一排气球arr,你能获得的最大分数是多少?
  13. 大数据周会-本周学习内容总结05
  14. OSINT + Python = 自定义黑客
  15. struts2 配置文件中 result的用法
  16. java计算机毕业设计中国民航酒店分销系统源码+系统+lw+数据库+调试运行
  17. b级车里有比迈腾空间更大的车吗?
  18. uniapp获取支付宝user_id - 支付宝提现 - 登录授权 - APP支付宝登陆 - H5支付宝授权
  19. 原生ajax crossO,总鳍鱼Crossopterygian
  20. Linux(CentOS)学习笔记

热门文章

  1. 三人表决器逻辑表达式与非_正则表达式 - 驰念
  2. HDU4730 We Love MOE Girls
  3. win10计算机设备感叹号,win10网络适配器出现感叹号的解决方法
  4. MySQL条件查询IN和NOT IN左右两侧包含NULL值的处理方式
  5. C’est lavie
  6. 城头土命适合做计算机电脑职业,土命人适合的职业
  7. 2021年度训练联盟热身训练赛第八场 自我总结
  8. 【萧蕊冰】ui设计和交互设计的区别是什么?
  9. 电子取证-----仿真技术
  10. Rational License Key Error的解决办法