音视频入门文章目录 html
图像互换格式主要分为两个版本,即图像互换格式 87a 和图像互换格式 89a。
图像互换格式 87a:是在 1987 年制定的版本。
图像互换格式 89a:是在 1989 年制定的版本。在这个版本中,为图像互换格式文档扩充了图形控制区块、备注、说明、应用程序接口等四个区块,并提供了对透明色和多帧动画的支持。git
如今咱们通常所说的 GIF 动画都是指 89a 的格式。github
GIF 包含的数据块:算法
本文全部分析,都是基于下面这张 GIF 图片。
用来分析的样例图片浏览器
十六进制编辑器app
GIF 的前 6 个字节内容是 GIF 的署名和版本号。
咱们能够经过前 3 个字节判断文件是否为 GIF 格式,后 3 个字节判断 GIF 格式的版本:编辑器
逻辑屏幕标识符配置了 GIF 一些全局属性,咱们经过读取解析它,获取 GIF 全局的一些配置。ide
逻辑屏幕标识符(7 个字节):工具
打包值,大小为 1 字节oop
从图中能够看出,这张 GIF 图片:
PS: Glide 中在读取了全局的宽高以后,忽略了颜色深度和分类标志,像素宽高比也只是读取,后续并无使用到。
全局颜色表,在逻辑屏幕标识以后,每一个颜色索引由三字节组成,按 RGB 顺序排列。
在 (2) 逻辑屏幕标识符(Logical Screen Descriptor)
中获得,全局颜色表大小是 8 个颜色,每一个颜色占 3 字节(R、G、B)。
接下来出现的是 21
FF
,特定于应用程序的信息,这个并无太大用处。惟一已知的公共文件是 Netscape 2.0 扩展(以下所述),用于循环动画GIF文件。
Netscape 2.0 循环块扩展必须当即出如今逻辑屏幕描述符的全局颜色表以后。它有19个字节长。
byte 1 : 33 (hex 0x21) GIF Extension code byte 2 : 255 (hex 0xFF) Application Extension Label byte 3 : 11 (hex 0x0B) Length of Application Block (eleven bytes of data to follow) bytes 4 to 11 : "NETSCAPE" bytes 12 to 14 : "2.0" byte 15 : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow) byte 16 : 1 (hex 0x01) bytes 17 to 18 : 0 to 65535, an unsigned integer in little-endian byte format. This specifies the number of times the loop should be executed. byte 19 : 0 (hex 0x00) a Data Sub-Block Terminator.
Application Extension 这 19 个字节基本上目前全部 GIF 都同样。
在 89a 版本,GIF 添加了图形控制扩展块。放在一个图象块(图象标识符)的前面,用来控制它后面的第一个图象的显示。
处置方法(Disposal Method):指出处置图形的方法:
用户输入能够是按回车键、鼠标点击等,能够和延迟时间一块儿使用,在设置的延迟时间内用户有输入则立刻继续进行,或者没有输入直到延迟时间到达而继续。
透明颜色标志(Transparent Color Flag):置位表示使用透明颜色。
从图中能够看出,这张 GIF 图片:
接下来出现的是 21
FE
,这容许你将 ASCII 文本嵌入到 GIF 文件,有时被用来图像描述、图像信贷或其余人类可读的元数据,如图像捕获的 GPS 定位。
下面是这张图片的 Comment Extension:
一个 GIF 文件中能够有多个图像块,每一个图像块就会有图像标识符,描述了当前帧的一些属性。下面咱们来看看图像标识符中包含的一些信息。
图像标识符以 ',' (0x2c) 做为开始标志。接着定义了当前帧的偏移量和宽高。
最后 5 个标志的意义分别为:
置位时标识紧接在图象标识符以后有一个局部颜色列表,供紧跟在它以后的一幅图象使用;值否时使用全局颜色列表,忽略 pixel 值。
从图中能够看出,这张 GIF 图片:
若是有局部颜色表,则跟 (3) 全局颜色表(Global Color Table)
同样的格式。
接下来就是图像数据(已使用 LZW 算法压缩,解压后才是真正的 基于颜色表的图像数据
)。
数据的第一个字节表示 LZW 编码初始表大小的位数,用于使用 LZW 算法解压数据。
后面的是图像数据块:
0
,表示数据结束了如上图所示:
最后一步,咱们将使用 LZW 算法解压图像数据块,并根据颜色表还原出整张图像(GIF 的一帧)的 RGB 文件。
须要删除标蓝色之外的全部字节,保存为rainbow-compressed.gif.frame
。
这个特性不起做用; 浏览器和图片处理应用程序,如 Photoshop 忽略它, GIFLIB 并不试图解释它。
标识 GIF 文件结束,固定值 0x3B。
当解析程序读到 0x3B 时,文件终结。
根据 (9) 基于颜色表的图像数据(Image Data)
,能够获得 GIF 一帧图像的数据(已使用 LZW 算法压缩)。
文 件 名:rainbow-compressed.gif.frame
文件大小:3428字节
这里直接使用 github.com/jefftime/lzw 这个库。
#include "stdio.h" #include "stdlib.h" #include "lzw/src/lzw.h" int main () { // LZW 编码初始表大小的位数:3 unsigned char code_size = 3; // GIF 一帧图像的数据压缩文件(rainbow-compressed.gif.frame)大小 long total_bytes; // GIF 一帧图像的数据压缩数据 unsigned char *img_compressed; // GIF 一帧图像的数据解压后的数据 unsigned char *img; // GIF 一帧图像的数据解压后大小 unsigned long decompressed_size; FILE *gif_compressed_frame = fopen("/Users/staff/Desktop/rainbow-compressed.gif.frame", "rb+"); fseek(gif_compressed_frame, 0L, SEEK_END); total_bytes = ftell(gif_compressed_frame); fseek(gif_compressed_frame, 0L, SEEK_SET); printf("Gif 一帧压缩文件大小:%li\n", total_bytes); img_compressed = malloc((unsigned long) total_bytes); fread(img_compressed, total_bytes, 1, gif_compressed_frame); // 进行 LZW 解压 lzw_decompress( code_size, total_bytes, img_compressed, &decompressed_size, &img ); printf("Gif 一帧解压文件大小:%li\n", decompressed_size); FILE *gif_decompressed_frame = fopen("/Users/staff/Desktop/rainbow-decompressed.gif.frame", "wb+"); fwrite(img, decompressed_size, 1, gif_decompressed_frame); fflush(gif_decompressed_frame); free(img_compressed); free(img); fclose(gif_compressed_frame); fclose(gif_decompressed_frame); return 0; }
解压后获得解压文件:rainbow-decompressed.gif.frame
解压后文件大小:490000字节 (700x700x1)
解压后文件中每个字节表明颜色表的一个颜色索引
#include "stdio.h" #include "stdlib.h" #include "lzw/src/lzw.h" // 颜色表 uint32_t rainbowColors[] = { 0XFF0000, // 赤 0X00FF00, // 绿 0XFFA500, // 橙 0XFFFF00, // 黄 0X0000FF, // 蓝 0X007FFF, // 青 0X8B00FF, // 紫 0X000000 // 黑 }; int main () { ...... FILE *gif_frame_rgb = fopen("/Users/staff/Desktop/rainbow-decompressed.gif.frame.rgb", "wb+"); for(int i = 0; i < decompressed_size; i++) { // 颜色索引值 unsigned char color_index = img[i]; // 根据颜色索引取出颜色表中的颜色 uint32_t color_rgb = rainbowColors[color_index]; // 当前颜色 R 份量 uint8_t R = (color_rgb & 0xFF0000) >> 16; // 当前颜色 G 份量 uint8_t G = (color_rgb & 0x00FF00) >> 8; // 当前颜色 B 份量 uint8_t B = color_rgb & 0x0000FF; fputc(R, gif_frame_rgb); fputc(G, gif_frame_rgb); fputc(B, gif_frame_rgb); } fflush(gif_frame_rgb); ...... }
这一步,获得了 GIF 一帧图像的 RGB 文件:rainbow-decompressed.gif.frame.rgb
GIF 一帧图像的 RGB 文件大小为:1470000 字节(700x700x3)
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-decompressed.gif.frame.rgb
参考资料:
内容有误?联系做者: