GIF图片格式详解(二)

gif历史请参考上一篇《GIF图片格式详解(一)》,或直接访问博客地址:https://blog.whatsroot.xyz/2023/12/16/all-about-gif/

文件格式概述

GIF格式采用调色板模式,即有一个颜色表,每种颜色可以使用RGB24格式存储,最多可以有256种颜色。这256种颜色构成了GIF的调色板(RGB24每个颜色3字节,256颜色则3*256=3 * 0x100 = 0x300个byte)。之后对于原始图像中的每个像素,不再使用具体的像素值,而是直接使用这个颜色在调色板中的索引值(索引值应该是0-255之间的数字)。

这样,对于某个颜色种类小于256种的图片,则可以实现无损压缩。对于超过256种颜色的图片来说,无论如何也是会产生信息损失的,只不过可以使用一些技巧把这种信息损失降到最低,比如使用Dither方法具体的方法就不在这里讨论了,可参考链接。

对于一张分辨率较高的图片,由于像素数目比较多,而颜色又总共只有256种,必然又大量重复的索引值,GIF使用了LZW这种无损编码算法进一步对数据进行了压缩。关于LZW专利,这里面还有一场早期的互联网斗争。LZW是被Unisys这家公司申请了专利的,但是当时没人注意到这一点,或者没人在意。
等到1994年,Unisys这家忽然宣布要所有使用LZW的公司都要付费。甚至到1999年时又修改了许可条款,未经允许任何人都无法使用。最终引发了一场“Burn GIFs”的运动,即要把所有GIF图片转换为PNG格式,客观上也促进了PNG格式的发展。甚至GIF也推出过方案使得索引值可以不经过LZW压缩,以此来规避专利问题。当然Unisys的专利已于2004年到期,现在GIF真正属于互联网了。

在GIF的89a版本中,添加了对透明度及动态图的支持。这里的透明度,只有0跟1两个值,即完全透明跟完全不透明。对动态图的支持,表明GIF支持多帧图像,且GIF支持每帧图像都有自己的调色板,这样就可以通过把原图划分为多个区域,每个区域都用256种颜色来表示,最后再利用透明度这个功能在不同的帧中只显示自己的部分,最终把不同的区域叠加起来,原则上就可以创造出远多余256种颜色。只不过采用这种方法需要多帧,会增大GIF本身体积,虽然原理上可行,但是实用价值不大。下面的图片用来展示这个方法。

具体文件格式

下面介绍GIF的具体文件格式,以a89为例,GIF的格式组成由下图,

注意实线框为必须项,虚线框为可选项。

上图是个极其简单的GIF图,它的分辨率只有10x10,最多只支持4种颜色,每种颜色用2位二进制数表示。

上面是这个GIF图的二进制数据,我们分别来看GIF的各个字段:

  • Header Bloack

数据为47 49 46 38 39 61,其实就是GIF89a的ASCII码。

  • Logical Screen Descriptor

数据为0A 00 0A 00 91 00 00, 逻辑屏幕描述符紧随标题之后,总共7个字节。

  • Canvas width, Canvas height

    这里的宽度跟高度不一定就是整个图像的宽度跟高度,如果分块的话,就是分块的宽度跟高度,这个字段的目的就是给分块提供可能。

  • Packed Filed

  • global color table flag
    全局颜色表标志,为0,表示没有全局颜色表。为1,表示有全局颜色表(我们的例子中有一个全局颜色表

  • color resolution.
    它代表的是颜色位深。只有在有全局颜色表时才有意义。如果这个字段的值是N,则位深为N+1, 能表示的颜色种类总数目将是2^(N+1)。
    样本图像中的001代表2位/像素;111将代表8位/像素。

  • sort flag
    非必须,如果为1,则表示全局颜色表中的颜色按照重要性递减的顺序排序,即图像中出现的频次递减。
    对解码有帮助,但不是必须的。

  • size of Global Color Table
    全局颜色表中的颜色个数,比如值为N,则颜色表个数为2^(N+1)

  • background color index

    背景颜色的索引,这个索引对应的全局颜色表中的颜色,将会被认为为背景

  • pixel aspect ratio

    像素宽度与高度的比值。这个参数几乎被所有现代浏览器忽略,具体用处可能与当年的模拟电视图像有关。

  • Global Color table

数据为FF FF FF FF 00 00 00 00 FF 00 00 00,使用RGB24格式表示的调色板,个数根据上面的size of Global Color Tabl来决定。

  • Graphics Control Extension

数据为21 F9 04 00 00 00 00 00,这部分是89a的扩展内容,目的是支持透明度以及动态图。本例中的图片没有透明度及动画,
这两方面的内容可参考Transparency and
Animation

  • extension introducer

固定为0x21

  • graphic control label

固定为0xF9

  • block size

总共的字节数,通常四个字节

  • Packed Filed

共1个字节,其中前三位保留,接下来的三位为disposal method, 用来制定切换到下一幅图像应该如何处理,共可表示0-7,动画图像的值是 1,这表明解码器应该保持当前图像不变,并在其上绘制下一幅图像。如果是 2,就意味着画布应恢复到背景色;3 则表示画布应恢复到绘制当前图像之前的状态。
据我所知,这个值并不被广泛支持。对于 4 到 7 的值,其行为还没有定义。如果这个图像不是动画,这些位通常会被设为 0,表示没有特定的处理方法。

第7位是用户输入标志,当其为 1 时,表示解码器会等待用户输入才会切换到下一幅图像。不过,在大多数情况下,这个位的值会是 0。最后一位是透明度标志。如果需要透明度,则需要设置为1,否则设置为0

  • delay time

用来控制动态图的帧率,单位是百分之一秒,即10毫秒。

  • Transparent Color index

透明颜色索引。指定哪个颜色为透明,哪个颜色就像涂了隐身药水变透明

  • Block terminator

块结束符号,通常00

  • Image Descriptor

数据为2C 00 00 00 00 0A 00 0A 00 00,
第一个字节是图像分隔符,每个图像描述符块都以 2C 作为起始值。接下来的 8 个字节用于表示随后图像的位置和大小。一个 GIF 文件可以包含多幅图像。在最初的 GIF 设计中,这些图像是为了组合到一个更大的虚拟画布上。然而,如今多幅图像通常用于制作动画。

每幅图像都从同一个图像描述符块开始,本例中这个块的长度恰好为 10 字节。在 GIF 中,图像并不一定要占据逻辑屏幕描述符定义的整个画布大小。因此,图像描述符块会指定图像在画布上的起始左边距和上边距位置。但现代的查看器和浏览器通常会忽略这些字段。接下来,这个块会指定图像的宽度和高度。这些值都是使用两字节、无符号、小端格式表示的。我们的示例图像显示,图像从 (0,0) 开始,宽度和高度均为 10 像素(这意味着图像占据了整个画布)。

最后一个字节又是一个Packed Filed。在我们的示例文件中,这个字节是 0,因此所有的子值都将是零。

  • local color table flag
    局部颜色表标志。将这个标志设置为 1 允许您指定随后的图像数据使用的颜色表与全局颜色表不同。

  • interlace flag
    交错标志。交错改变了图像呈现在屏幕上的方式,可以减少令人讨厌的视觉闪烁,视觉闪烁的原因,又要追溯到上世纪模拟显示器的扫描方式。
    交错在显示器上的效果是,先显示图像其中一部分,这样观众可以先看到一个模糊的图像,然后逐渐清晰,最后完全显示,也是在那个宽带极其有限的情况下的产物。
    防止屏闪可以不考虑,因为现在的显示器不会有这个问题。关于显示效果举个例子一看就明白了,左边是顺序显示,右边是交错显示。

  • 其余sort flag, size of local color table
    与前文描述一致,只不过是局域颜色表
  • Local Color Table

    与全局颜色表一致,需要local color table flag为1生效

  • Image Data

数据为02 16 8C 2D 99 87 2A 1C DC 33 A0 02 75 EC 95 FA A8 DE 60 8C 04 91 4C 01 00,

通常情况下这部分才是GIF最主要的内容,只不过我们举的例子太小了所这这部分内容较少,
需要说明的是这部分需要LZW编码。具体编码方案这里不做介绍。

  • Plain Text extension

数据内容为:21 01 0C 00 00 00 00 64 00 64 00 14 14 01 00 0B 68 65 6C 6C 6F 20 77 6F 72 6C 64 00

GIF 89a标准允许在接下来的图像上添加文本标题。然而,这个功能并没有广泛流行;像 Photoshop 这样的浏览器和图像处理软件通常会忽略这一功能。就像所有扩展块类型一样,这个块以扩展引入符开始,这个值总是 21。下一个字节是纯文本标签, 这个值 01, 用于将纯文本扩展与所有其他扩展区分开来。接下来的字节是块大小,表示实际文本数据开始之前有多少字节,或换句话说现在可以跳过多少字节。字节值可能是 0x0C,这意味着应该向前跳过 12 个字节。随后的文本被编码在数据子块中,当到达长度为 0 的子块时,该块结束。

  • Application extension

数据内容为:21 FF 0B 4E 45 54 53 43 41 50 45 32 2E 30 03 01 05 00 00,
GIF89规范允许在 GIF 文件本身中嵌入特定于应用程序的信息。这种能力并没有得到广泛使用。
大约唯一已知的公开使用是就是前面提到的 Netscape 2.0 扩展,它用于循环播放动画 GIF 文件

  • Comment Extension

数据内容为:21 FE 09 62 6C 75 65 62 65 72 72 79 00

GIF89 规范中的最后一个扩展类型是评论扩展。这允许你在 GIF 文件中嵌入 ASCII 文本,通常用于添加图像描述、图像版权信息或其他人类可读的元数据,如图像捕获的 GPS 位置。这个扩展的第一个字节是扩展引入符,编号为 21。接下来的一个字节总是 FE,代表评论标签。然后我们直接跳到包含评论ASCII 字符代码的数据子块。从例子中我们可以看到,这里有一个长度为 9 字节的数据子块。如果你将这些字符代码翻译出来,会发现评论内容是“blueberry”。最后一个字节 00 表示一个没有后续字节的子块,标志着我们已经到达了这个块的末尾。

  • Trailer

数据内容为:3B

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/58715.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TypeScript 基础语法及使用

文章目录 1、概述2、快速使用3、常用类型4、基础类型5、联合类型6、函数类型7、对象类型 & 接口interface 1、概述 TypeScript(简称 TS)是JavaScript的超集(继承了JS全部语法)是微软开发的开源编程语言,可以在任何…

深入了解决策树:机器学习中的经典算法

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

基于Java Web的传智播客crm企业管理系统的设计与实现

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

如何学习C++游戏开发

学习C游戏开发是一个涉及多个领域的复杂过程,包括编程、游戏设计、图形学等。 1. **学习C基础**: - 掌握C的基本语法和面向对象编程。 - 学习C标准库,特别是STL(标准模板库)。 2. **理解游戏开发概念**&#xf…

RabbitMQ 篇-深入了解 RabbitMQ 安装以及 SpringAMQP 的基础使用(声明队列和交换机、发送接收消息、配置 JSON 消息转化器)

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 RabbitMQ 初识 1.1 RabbitMQ 安装 2.0 数据隔离 2.1 用户管理 2.2 virtual host 虚拟主机 3.0 SpringAMQP 3.1 RabbitMQ 配置 3.2 发送消息 3.3 接收消息 3.4 Wor…

基础归一化方法 数学理论及其matlab代码

归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量。在多种计算中都经常用到这种方法。以下是常见的基础归一化方法:Min-Max 归一化,Z-Score 归一化、小数定标归一化、…

漫漫数学之旅038

文章目录 经典格言数学习题古今评注名人小传 - 古斯塔夫福楼拜 经典格言 诗歌是一门像几何一样严格的科学。——古斯塔夫福楼拜(Gustave Flaubert) 古斯塔夫福楼拜将诗歌比作几何学,强调了诗歌创作的严谨性。他认为诗歌不仅仅是情感的流露&a…

前端md5加密

npm下载 npm install --save ts-md5页面引入 import { Md5 } from ts-md5使用 const md5PwdMd5.hashStr("123456")md5Pwd(加密后的数据) .toUpperCase()方法转大写

植物神经紊乱不用怕,这些维生素来帮你!

在现代快节奏的生活中,植物神经紊乱已成为一种常见的健康问题。你是否经常感到焦虑、失眠、疲劳,甚至消化不良?这些可能都是植物神经紊乱的表现。幸运的是,通过适当补充维生素,我们可以有效缓解症状,恢复身…

华为ENSP--ISIS路由协议

项目背景 为了确保资源共享、办公自动化和节省人力成本,公司E申请两条专线将深圳总部和广州、北京两家分公司网络连接起来。公司原来运行OSFP路由协议,现打算迁移到IS-IS路由协议,张同学正在该公司实习,为了提高实际工作的准确性和…

二分查找习题篇(下)

二分查找习题篇(下) 1.山脉数组的峰顶索引 题目描述: 给定一个长度为 n 的整数 山脉 数组 arr ,其中的值递增到一个 峰值元素 然后递减。 返回峰值元素的下标。 你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。 示例 1: 输入&#xf…

playground.tensorflow神经网络可视化工具

playground.tensorflow 是一个可视化工具,用于帮助用户理解深度学习和神经网络的基本原理。它通过交互式界面使用户能够构建、训练和可视化简单的神经网络模型。以下是一些主要的数学模型和公式原理,它们在这个平台中被应用: 1. 线性模型 线…

LSM-TREE和SSTable

一、什么是LSM-TREE LSM Tree 是一种高效的写优化数据结构,专门用于处理大量写入操作 在一些写多读少的场景,为了加快写磁盘的速度,提出使用日志文件追加顺序写,加快写的速度,减少随机读写。但是日志文件只能遍历查询…

SDL线程

文章目录 SDL线程相关 SDL线程相关 SDL线程创建:SDL_CreateThreadSDL线程等待: SDL_WaitThreadSDL互斥锁 :SDL_CreateMutex/SDL_DestoryMutexSDL锁定互斥: SDL_LockMutex/SDL_UnlockMutexSDL条件变量:SDL_CreateCond/SDL_DestoryCondSDL条件变量 等待通知: SDL_Con…

DevExpress JS ASP.NET Core v24.1亮点 - 支持DateOnly/TimeOnly类型

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NET Core,jQuery,Knockout等)构建交互式的Web应用程序。从Angular和Reac&#xff0c…

【HarmonyOS】键盘遮挡输入框UI布局处理

【HarmonyOS】键盘遮挡输入框UI布局处理 问题背景: 在开发输入框UI时,特别是登录页面的密码输入框靠下,或者是评论底部的pop弹框。 当我们输入框获得焦点后,键盘自下而上显示,一般情况下会遮挡住我们的UI布局。 导致…

Rust重写万物之——从头开始编写浏览器引擎

一款用 Rust 编写的全新“轮子”最近备受关注—— 因不满大公司垄断,Gosub 项目团队用 Rust 从头开始编写了一个新的浏览器引擎,目前 star 数已超过 3k。 Gosub 项目的诞生是因为不少用户对当前的 Web 浏览器现状感到不满。 尽管市面上有许多浏览器可供选择,但其中大多数…

抗辐照MCU芯片工艺解析:如何保障芯片的可靠性

行星探索、轨道飞行器任务和空间研究在内的太空项目需要创新的航天器系统技术提供通信与处理功能。随着商业航天的发展,对于航天电子系统需要考虑高可靠与高性能的同时,还需要考虑降低开发成本和缩短上市时间。 以MCU芯片AS32A401为例,该芯片…

python(自用查看版)

目录 1.注意事项 1.1 python的除法不是整除,得到的是浮点数 1.2算术符号基于数学的算术优先级。具体可自行查看。 1.3注释 1.4缩进 1.5换行 1.6常见关键字 1.7续行符 1.8报错 1.9赋值 1.10比较运算符 2.常量和表达式 3.变量 4.数据类型 4.1整型int …

微信小程序,点击bindtap事件后,没有跳转到详情页,有可能是app.json中没有正确配置页面路径

文章目录 1、index.wxml2、index.js检查点1. 确保目标页面存在2. 确保页面路径配置正确3. 检查页面接收参数productDetail.jsproductDetail.wxmlproductDetail.wxss 总结 1、index.wxml <!-- 商品搜索结果卡片容器 --><view class"search-result"><bl…