gif编码协议图解和js实现gif播放控制器逻辑

499 阅读2分钟

示例地址 zaqmjuop.github.io/libgif/

090592ebd01ac1e425b2766989040f801001718.gif

从gif文件读取图像数据

gif内容示例

2af3a545df78fb69422635fbfdda4b481082276.png

从字符串读取二进制数字的方法

// 字符转数字
'GIF'.charCodeAt(0) // 71
'GIF'.charCodeAt(1) // 73
'GIF'.charCodeAt(2) // 70

// 数字转字符
String.fromCharCode(71) // 'G'
String.fromCharCode(73) // 'I'
String.fromCharCode(70) // 'F'

// 十进制转2进制
(247).toString(2) // '11110111'

unsigned 类型: 256进制的2位数,比如 [144, 1] 的取值是 144 + 1 * 256 = 400

GIF89a编码内容结构

  • 整体结构

截屏2023-04-05 上午10.55.48.png

  • 连续字块

截屏2023-04-05 上午10.56.43.png

  • 文件头块

截屏2023-04-05 上午10.57.35.png

  • 图像内容块

截屏2023-04-05 上午11.09.03.png

  • 像素插行

GIF89a的像素插行分4步,以正常像素行号 [0, 1, 2, 3, 4, ..., 19]为例

  1. 从第 0 行开始间隔 8 行插入,即像素行号排序 0, 8, 16

  2. 从第 4 行开始间隔 8 行插入,即像素行号排序 4, 12

  3. 从第 2 行开始间隔 4 行插入,即像素行号排序 2, 6, 10, 14, 18

  4. 从第 1 行开始间隔 2 行插入,即像素行号排序 1, 3, 5, 7, 9, 11, 13, 15, 17, 19

截屏2023-04-05 上午10.59.35.png

截屏2023-04-05 上午10.59.56.png

扩展块
  • 应用程序扩展块

截屏2023-04-05 上午11.01.09.png

  • 图形扩展块,作用范围是紧跟着的帧图像块

截屏2023-04-05 上午11.01.41.png

  • 注释扩展块

截屏2023-04-05 上午11.02.10.png

  • 纯文本扩展块

扩展块描述的内容是一个带有位置、大小、颜色的文本,作用像是图片的水印文字,但我从没见过出现过这个扩展块

  • 文件结束符:';'即59

2. 播放控制

理想的执行过程应该是下载一帧,解码一帧,渲染一帧。所以下载、解码和播放应该是并行执行。

解码器解码时,解码进度可能会超过下载进度,数据流读取器读取方法的读取位置就会到源数据的末位之后,那么就要等待下载数据增加后再返回,所以流读取器读取方法是异步函数。

播放器播放时,播放进度可能超过解码进度,所以播放函数要轮询从解码缓存池读取解码数据,再播放下一帧

截屏2023-04-05 上午11.04.27.png

3. gif编码用到的LZW压缩

  • 示例参数

截屏2023-04-05 上午11.05.22.png

  • 示例结果

截屏2023-04-05 上午11.06.26.png

  • 解压缩过程

截屏2023-04-05 上午11.07.00.png

  • 示例运行过程

截屏2023-04-05 上午11.07.42.png