腾讯技术分享:GIF动图技术详解及手机QQ动态表情压缩技术实践

腾讯技术分享:GIF动图技术详解及⼿机QQ动态表情压缩技术实践
本⽂来⾃腾讯前端开发⼯程师“ wendygogogo”的技术分享,作者⾃评:“在Web前端摸爬滚打的码农⼀枚,对技术充满热情的菜鸟,致⼒为⼿Q的建设添砖加⽡。”
1、GIF格式的历史
GIF ( Graphics Interchange Format )原义是“图像互换格式”,是 CompuServe 公司在1987年开发出的图像⽂件格式,可以说是互联⽹界的⽼古董了。
本来,随着⽹络带宽的拓展和视频技术的进步,这种图像已经渐渐失去了市场。可是,近年来流⾏的表情包⽂化,让⽼古董 GIF 图有了新的⽤武之地。
表情包通常来源于⼿绘图像,或是视频截取,⽬前有很多⽅便制作表情包的⼩⼯具。
这类图⽚通常具有⽂件体积⼩,内容简单,兼容性好(⽆需解码⼯具即可在各类平台上查看),对画质要求不⾼的特点,刚好符合 GIF 图的特性。
所以,⽼古董 GIF 图有了新的应⽤场景。
2、相关⽂章
《腾讯技术分享:社交⽹络图⽚的带宽压缩技术演进之路》
《QQ⾳乐团队分享:Android中的图⽚压缩技术详解(上篇)》
《QQ⾳乐团队分享:Android中的图⽚压缩技术详解(下篇)》
《腾讯原创分享(⼀):如何⼤幅提升移动⽹络下⼿机QQ的图⽚传输速度和成功率》
《腾讯技术分享:腾讯是如何⼤幅降低带宽和⽹络流量的(图⽚压缩篇)》
《全⾯掌握移动端主流图⽚格式的特点、性能、调优等》
《基于社交⽹络的Yelp是如何实现海量⽤户图⽚的⽆损压缩的?》
3、技术需求场景
新的应⽤场景带来新的需求,本⽂所要探究的技术和要解决的问题来源于某个真实的业务场景下——即为⽤户批量推送GIF表情包的功能需求。
⼀批图像⼤约有200-500张,以缩略图列表的形式展⽰在客户端。
根据我们使⽤测试数据进⾏的统计 GIF 图表情包的尺⼨⼤部分在200k-500k之间,批量推送的⼀个重要问题就是数据量太⼤,因此,我们希望能够在列表⾥展⽰体积较⼩的缩略图,⽤户点击后,再单独拉取原图。
传统的 GIF 缩略图是静态的,通常是提取第⼀帧,但在表情包的情形下,这种⽅式不⾜以表达出图⽚中信息
⽐如下⾯的例⼦:
(左为原始GIF动态图,右为GIF的第⼀帧)
第⼀帧完全看不出重点啊!
所以,我们希望缩略图也是动态的,并尽可能和原图相似。
对于传统图⽚来说,⽂件⼤⼩⼀般和图⽚分辨率(尺⼨)正相关,所以,⽣成缩略图最直观的思路就
是缩⼩尺
⼨,resize⼤法。调盘
但是在 GIF 图的场合,这个⽅式不再⾼效,因为 GIF 图的⽂件⼤⼩还受到⼀个重要的因素制约——帧数
以这张柴⽝表情为例,原图宽度200,尺⼨1.44M,等⽐缩放到150之后,尺⼨还是1.37M,等⽐缩放到100,相当于尺⼨变为原来的四分之⼀,体积还是749K。
可见,resize⼤法的压缩率并不理想,收效甚微。
⽽且,我们所得到的⼤部分表情图素材,分辨率已经很⼩了,为了保证客户端展⽰效果,不能够过度减少尺⼨,不然图⽚会变得模糊。
所以,想要对GIF图进⾏压缩,只能从别的⽅向⼊⼿。
4、GIF技术详解:拆解GIF格式
4.1 基本
想要压缩⼀个⽂件,⾸先要了解它是如何存储的。毕竟,编程的事,万变不离其宗嘛。
作为⼀种古⽼的格式,GIF的存储规则也相对简单,容易理解。
⼀个GIF⽂件主要由以下⼏部分组成:
1)⽂件头;
2)图像帧信息;
3)注释。
下⾯我们来分别探究每个部分。
4.2 ⽂件头
GIF格式⽂件头和⼀般⽂件头差别不⼤,也包含有:
1)格式声明;
2)逻辑屏幕描述块;
3)全局调⾊盘;
格式声明:
Signature 为“GIF”3 个字符;Version 为“87a”或“89a”3 个字符。
逻辑屏幕描述块:
前两字节为像素单位的宽、⾼,⽤以标识图⽚的视觉尺⼨。
Packet⾥是调⾊盘信息,分别来看:
1)Global Color Table Flag为全局颜⾊表标志,即为1时表明全局颜⾊表有定义;
2)Color Resolution 代表颜⾊表中每种基⾊位长(需要+1),为111时,每个颜⾊⽤8bit表⽰,即我们熟悉的RGB表⽰法,⼀个颜⾊三字节;
3)Sort Flag 表⽰是否对颜⾊表⾥的颜⾊进⾏优先度排序,把常⽤的排在前⾯,这个主要是为了适应⼀些颜⾊解析度低的早期渲染器,现在已经很少使⽤了;
4)Global Color Table 表⽰颜⾊表的长度,计算规则是值+1作为2的幂,得到的数字就是颜⾊表的项数,取最⼤值111时,项数=256,也就是说GIF格式最多⽀持256⾊的位图,再乘以Color Resolution算出的字节数,就是调⾊盘的总长度。
这四个字段⼀起定义了调⾊盘的信息。
Background color Index 定义了图像透明区域的背景⾊在调⾊盘⾥的索引。
Pixel Aspect Ratio 定义了像素宽⾼⽐,⼀般为0。
什么是调⾊盘?我们先考虑最直观的图像存储⽅式,⼀张分辨率M×N的图像,本质是⼀张点阵,如果采⽤Web最常见的RGB三⾊⽅式存储,每个颜⾊⽤8bit表⽰,那么⼀个点就可以由三个字节(3BYTE = 24bit)表达,⽐如0xFFFFFF可以表⽰⼀个⽩⾊像素点,0x000000表⽰⼀个⿊⾊像素点。
如果我们采⽤最原始的存储⽅式,把每个点的颜⾊值写进⽂件,那么我们的图像信息就要占据就是3×M×N字节,这是静态图的情况,如果⼀张GIF图⾥有K帧,点阵信息就是3×M×N×K。
下⾯这张兔⼦snowball的表情有18帧,分辨率是200×196,如果⽤上述⽅式计算,⽂件尺⼨⾄少要689K。
但实际⽂件尺⼨只有192K,它⼀定经历过什么……
我们可以使⽤命令⾏图⽚处理⼯具gifsicle来看看它的信息:
gifsicle -I snowball.gif >
gifsicle -I snowball.gif >
我们得到下⾯的⽂本:
5.gif 19 images
logical screen 200x196
global color table (128)
background 93
loop forever
extensions 1
+ image #0 200x196 transparent 93
disposal asis delay 0.04s
+ image #1 200x188 transparent 93
disposal asis delay 0.04s
........
可以看到,global color table 128就是它的调⾊盘,长度128。
为了确认,我们再⽤⼆进制查看器查看⼀下它的⽂件头:
可以看到Packet⾥的字段的确符合我们的描述。
在实际情况中,GIF图具有下⾯的特征:
1)⼀张图像最多只会包含256个RGB值;
2)在⼀张连续动态GIF⾥,每⼀帧之间信息差异不⼤,颜⾊是被⼤量重复使⽤的。
在存储时,我们⽤⼀个公共的索引表,把图⽚中⽤到的颜⾊提取出来,组成⼀个调⾊盘,这样,在存储真正的图⽚点阵时,只需要存储每个点在调⾊盘⾥的索引值。
如果调⾊盘放在⽂件头,作为所有帧公⽤的信息,就是公共(全局)调⾊盘,如果放在每⼀帧的帧信息中,就是局部调⾊盘。GIF格式允许两种调⾊盘同时存在,在没有局部调⾊盘的情况下,使⽤公共调⾊盘来渲染。
这样,我们可以⽤调⾊盘⾥的索引来代表实际的颜⾊值。
⼀个256⾊的调⾊盘,24bit的颜⾊只需要⽤9bit就可以表达了。
调⾊盘还可以进⼀步减少,128⾊,64⾊,etc,相应的压缩率就会越来越⼤……
还是以兔⼦为例,我们还可以尝试指定它的调⾊盘⼤⼩,对它进⾏重压缩:
gifsicle --colors=64 5.gif > 5-64.gif
gifsicle --colors=32 5.gif > 5-32.gif
gifsicle --colors=16 5.gif > 5-16.gif
gifsicle --colors=2 5.gif > 5-2.gif
......
依然使⽤gifsicle⼯具,colors参数就是调⾊盘的长度,得到的结果:
注意到了2的时候,图像已经变成了⿊⽩⼆值图。
居然还能看出是个兔⼦……
所以我们得出结论——如果可以接受牺牲图像的部分视觉效果,就可以通过减⾊来对图像做进⼀步压缩。
⽂件头所包含的对我们有⽤的信息就是这些了,我们继续往后看。
4.3 帧信息描述
帧信息描述就是每⼀帧的图像信息和相关标志位,在逐项了解它之前,我们⾸先探究⼀下帧的存储⽅式。
我们已经知道调⾊盘相关的定义,除了全局调⾊盘,每⼀帧可以拥有⾃⼰的局部调⾊盘,渲染顺序更优先,它的定义⽅式和全局调⾊盘⼀致,只是作⽤范围不同。
直观地说,帧信息应该由⼀系列的点阵数据组成,点阵中存储着⼀系列的颜⾊值。点阵数据本⾝的存储也是可以进⾏压缩的,GIF图所采⽤的是LZW压缩算法。
这样的压缩和图像本⾝性质⽆关,是字节层⾯的,⽂本信息也可以采⽤(⽐如常见的gzip,就是LZW和哈夫曼树的⼀个实现)。
基于表查询的⽆损压缩是如何进⾏的?基本思路是,对于原始数据,将每个第⼀次出现的串放在⼀个串表中,⽤索引来表⽰串,后续遇到同样的串,简化为索引来存储(串表压缩法)。
举⼀个简单的例⼦来说明LZW算法的核⼼思路。
有原始数据:ABCCAABCDDAACCDB
可以看出,原始数据⾥只包括4个字符A,B,C,D,四个字符可以⽤2bit的索引来表⽰,0-A,1-B,2-C,3-D。
原始字符串存在重复字符,⽐如AB,CC,都重复出现过。⽤4代表AB,5代表CC,上⾯的字符串可以替代表⽰为
45A4CDDAA5DB
这样就完成了压缩,串长度从16缩减到12。对原始信息来说,LZW压缩是⽆损的。
除了采⽤LZW之外,帧信息存储过程中还采取了⼀些和图像相关的优化⼿段,以减⼩⽂件的体积,直观表述就是——公共区域排除、透明区域叠加
这是ImageMagick官⽅范例⾥的⼀张GIF图:
根据直观感受,这张图⽚的每⼀帧应该是这样的:

本文发布于:2024-09-21 10:40:01,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/371242.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:图像   技术   压缩   信息
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议