Jun
11
上一回讲到在客户端中主流的静态图片资源PNG的使用情况与压缩方式。当然啦,PNG这种前端各方面都广泛支持,并且大家都使用得很满意的格式,大家都很喜欢很愉快的使用啦。而对于稍微没那么常用的动态图片资源,虽然主流的是gif,然而由于各种条件限制大家都使用得特别不开心,各自都在提出新的解决方案。
现在,除了gif,还有继承于png的apng,这也是我比较喜欢的,png的兄弟mng,还有webp的高级版本也支持动图。在这么多方案中,虽然自己都说自己好,不过我站我的APNG还是需要充足的理由,因此接下来由APNG展开讲讲各大客户端动图策略的异同和对比。
APNG
是普通png的一个拓展,上一次说了,png的主体就是一个一个块(chunk),那么增加更多的数据块,就可以描述更多的信息——这就是apng对png的拓展方式。因此,对于一个普通的png,我们必要的块是:
IHDR IDAT IEND
这些可以描述一幅画。而apng是这样的:
IHDR ACTL [FCTL IDAT] [FCTL FDAT] [FCTL FDAT] ... IEND
看得懂png的格式,再看这个白皮书就没问题了(https://wiki.mozilla.org/APNG_Specification)。虽然一下子看起来复杂了很多,多出了3中数据块,不过我们也可以清晰的整理出它们的作用:
ACTL:其实是对IHDR的补充,IHDR描述的是画面静态的信息,而ACTL描述了画面动态的信息,比如帧数,是否循环等信息。
FCTL:方括号我这里表示的是每一帧的信息,FCTL就是表述当前帧的高宽,延迟之类的信息的。
FDAT:和IDAT一模一样的东西,也就是记录每一帧的图像数据的。唯一的不同是IDAT是完整的图像,而后面的帧FDAT其实是图像differ。
多了这三部分,这样就是一个最简且完整的动图格式了。并且这个格式的第一帧的图像无缝兼容普通png的显示,降级方案也非常自然,格式清晰简明不复杂。
APNG vs GIF
首先,gif的文件格式和png的文件格式非常相似,同样是以块为单位储存数据,同样是无损储存数据,同样是lzw的分支算法进行的无损压缩,特别是对于png8来说,几乎是一模一样的。
当然,gif相对于png天然的劣势是不支持全alpha通道颜色,抛开这个不谈,我们来看apng8和gif的区别。
1. 仔细分析两种格式的数据块结构,gif的逻辑数据和apng8的逻辑数据内容一模一样,不过gif还有一个二次打包拆分的过程,因此从文件结构上说会比apng8稍大。
2. gif除了全局的颜色索引,还可以为每一帧设置颜色索引来实现更丰富的颜色。当然,对应的文件大小会变得更大。因此一般情况下gif压缩都会把私有颜色索引压掉强行256色。
3. apng和gif最大的区别是在后续帧differ计算储存方式上,虽然实际无法比较,但是可以细讲:
a. gif储存的differ是像素颜色的differ,依赖上下帧渲染可以叠加的特性,下一帧透明的部分显示了上一帧的颜色来实现压缩数据。话说这个计算方式对带alpha的十分不友好。
b. 而apng的differ是最小矩形differ,两张图变化的最小矩形画面被储存了起来。
因此如下图情况,图1和图2是前后一帧:
图3即gif储存的differ,可以看到只需要储存不同的像素,其它的地方透明就可以了。而图4是apng储存的differ,由于最小变化矩形是全图,所以没办法只有储存全图了。显然这种情况下gif的differ优化率远大于apng。
而另一种情况如下:
图1到图2变化的像素相对集中,那么gif还需要储存全图的情况下,apng只需要储存很小一张图像就可以解决问题了。这种情况下apng的优化率会大于gif。
当然,我们会考虑将这两种differ方式结合起来。不过gif是牺牲了alpha通道做到的,所以已经很困难了。而apng则需要为每个像素再加一位来表示它是否用上一帧的,明显会增加新的数据,对于本来就是索引表的每个像素增加新的数据,到底好不好这可就不好说了.....反正apng并没有这么做。
4. 另外对于app来说,还需要考虑两种动图的解析性能成本——当然,本来文件结构就很相似,他们这方面成本自然无法比较。
因此总的来说,对于不带透明通道的动图,gif和apng彼此彼此不分伯仲,但是带透明通道的当然就不用话说了。
APNG vs MNG
mng又是啥,mng是png的兄弟格式,是为了覆盖所有的图片格式而诞生的。它和png类似,也是chunk性质的,不过这个就复杂很多很多了(http://www.libpng.org/pub/mng/spec/),基本没法详细讲解了。在mng里面,可以有png,jpg等多种单个图像,通过图层,变换,动画等各种方式来组成这个复杂的mng文件。
1. 和apng相比,mng就想对单层的静态图片多了一层封装结构一样,而它内部实际的图像数据储存块并没有创新,因此对于相同的图片,mng文件会大于apng。相比起来mng就想是一个psd一样是万能的封装,当然大了。
2. 由于可以通过图层和变化来实现不同帧的图像复用,因此在特定的动画场景下,mng的动态图像会小于apng,不过这种东西无法通过算法或者自动的方式换转得到,只能由图像生产者直接输出,因此就算遇到了适用情况(比如大部分表情包),是否有能力转换到较小的mng图像还是一个非常存疑的问题。
3. 对于app来说,再考虑解析成本的话,mng这样复杂的格式显然会大大增加解析性能消耗和内存。
因此在没有必要的情况下,几乎不太可能选择mng。
APNG vs WEBP
首先用apng和webp相比较似乎不太科学,毕竟apng和gif和mng对应的是png,是无损图像格式的动态化方案;而webp对应的是jpg,是有损图像的方案。就想png和jpg在互联网上各有各的长处相安无事一样,webp与apng同时存在并没有什么问题。不过既然要选优,当然也做一下对比比较好。
简单介绍一下webp,它是谷歌源自vp8视频编码格式拓展出来的图像格式,它的核心图像储存算法就是vp8编码了,动图的webp拓展的储存方式当然也就和vp8的视频无异(类似于webm)。不过因为是单纯的图像储存,所以实际文件结构并不想mng一样过于冗余繁琐。同时,作为静态图片的webp现在在互联网上的呼声是最高的,因此,作为高级版本的动态版webp,也会顺带一起支持。
1. 那么和apng相比,由于是类似于视频编码方式的无损或者有损压缩,确实比普通的lwxxx压缩方式高端很多,并且有类似于视频编码的differ帧计算技术,所以从实际各方测试效果表明,绝大部分情况下,webp的动态图像是小于apng的,并且越是复杂的图案和动态变化,这个优势越明显。
2. 另外由于谷歌的大力推广,webp的相关工具链的成熟度远大于apng,大概是webp>>apng>mng。因此对于图像向webp的转换,并没有太大的难度。
3. 另外app的解析成本的话,根据疼讯的测试,大概在普通png的5倍左右,实际占用内存和显示性能应该也会差。嗯可以理解,毕竟是一个非常复杂的储存结构了。
因此,总的来看webp确实是一个优于apng的方案,在原生支持的情况下,采用webp基本确认优于apng,不过现在的形势并不那么确定。
图片序列
事实上在app和web上,对于动态图像的处理并不是以上的方案,各种图片序列也是最常见的方案。
图片序列是储存在同一张图的多帧图像通过不断修改图像的锚点位置来实现动画(css),或者直接加载不同的图像。比如b站收藏按钮动画就是这样的一张图:
1. 这样储存的图像占用储存显然是最大的,但是对应换取的是最快的解析和渲染速度,占用内存也并不高。
2. 图像序列的第二个好处是可以很方便的进行速度控制和动画进度控制,并实现图像复用。对于各种粘手场景的动画操作(比如下拉刷新的动画),这是很有必要的。
3. 在app和web上,图片序列永远是最方便和最通用的方案,永远不会有各种奇怪的问题。
巧妙掠过的问题
刚才讲apng,mng和动态webp时,我巧妙掠过了一个最关键的问题,即各端兼容性问题,在这里我们再来看看吧。
APNG
apng现在主要是Mozilla在支持...它甚至不被png组织本身支持。因此它现在的支持性主要在ff上。
原生支持:Firefox Safari(>=8) Opera(旧版)
社区支持:apng-canvas实现在所有现代浏览器上支持 japng_android实现安卓 APNGKit实现iOS
MNG
mng是png组织官方的推荐格式,不过实际上由于它太复杂了,它在这三种格式中发展得最差。
原生支持:Firefox(旧版)
社区支持:没有,不过ios理论上可以直接引用官方c代码
WEBP
webp是谷歌主推的,因此基本上chrome系的浏览器都没问题。
原生支持:Chrome Opera(新版) Android(>=6)
社区支持:WebPJS实现在所有现代浏览器上支持 SDWebImage提供ios上兼容
结论部分
0. gif再见。
1. mng还是算了,再见。
2. webp有谷歌支持,可能会发展的很好,但是动画webp特性较新,支持性存疑。
3. apng有Mozilla支持,最近也打通了让苹果支持,因此也比较看好。压缩率可能比webp低,性能比webp高,向前兼容性好。
综上所述,我站APNG,通过社区支持也能做到最好的性能和兼容性的平衡。不过要我做产品,我还是选择gif和图片序列。
现在,除了gif,还有继承于png的apng,这也是我比较喜欢的,png的兄弟mng,还有webp的高级版本也支持动图。在这么多方案中,虽然自己都说自己好,不过我站我的APNG还是需要充足的理由,因此接下来由APNG展开讲讲各大客户端动图策略的异同和对比。
APNG
是普通png的一个拓展,上一次说了,png的主体就是一个一个块(chunk),那么增加更多的数据块,就可以描述更多的信息——这就是apng对png的拓展方式。因此,对于一个普通的png,我们必要的块是:
IHDR IDAT IEND
这些可以描述一幅画。而apng是这样的:
IHDR ACTL [FCTL IDAT] [FCTL FDAT] [FCTL FDAT] ... IEND
看得懂png的格式,再看这个白皮书就没问题了(https://wiki.mozilla.org/APNG_Specification)。虽然一下子看起来复杂了很多,多出了3中数据块,不过我们也可以清晰的整理出它们的作用:
ACTL:其实是对IHDR的补充,IHDR描述的是画面静态的信息,而ACTL描述了画面动态的信息,比如帧数,是否循环等信息。
FCTL:方括号我这里表示的是每一帧的信息,FCTL就是表述当前帧的高宽,延迟之类的信息的。
FDAT:和IDAT一模一样的东西,也就是记录每一帧的图像数据的。唯一的不同是IDAT是完整的图像,而后面的帧FDAT其实是图像differ。
多了这三部分,这样就是一个最简且完整的动图格式了。并且这个格式的第一帧的图像无缝兼容普通png的显示,降级方案也非常自然,格式清晰简明不复杂。
APNG vs GIF
首先,gif的文件格式和png的文件格式非常相似,同样是以块为单位储存数据,同样是无损储存数据,同样是lzw的分支算法进行的无损压缩,特别是对于png8来说,几乎是一模一样的。
当然,gif相对于png天然的劣势是不支持全alpha通道颜色,抛开这个不谈,我们来看apng8和gif的区别。
1. 仔细分析两种格式的数据块结构,gif的逻辑数据和apng8的逻辑数据内容一模一样,不过gif还有一个二次打包拆分的过程,因此从文件结构上说会比apng8稍大。
2. gif除了全局的颜色索引,还可以为每一帧设置颜色索引来实现更丰富的颜色。当然,对应的文件大小会变得更大。因此一般情况下gif压缩都会把私有颜色索引压掉强行256色。
3. apng和gif最大的区别是在后续帧differ计算储存方式上,虽然实际无法比较,但是可以细讲:
a. gif储存的differ是像素颜色的differ,依赖上下帧渲染可以叠加的特性,下一帧透明的部分显示了上一帧的颜色来实现压缩数据。话说这个计算方式对带alpha的十分不友好。
b. 而apng的differ是最小矩形differ,两张图变化的最小矩形画面被储存了起来。
因此如下图情况,图1和图2是前后一帧:
图3即gif储存的differ,可以看到只需要储存不同的像素,其它的地方透明就可以了。而图4是apng储存的differ,由于最小变化矩形是全图,所以没办法只有储存全图了。显然这种情况下gif的differ优化率远大于apng。
而另一种情况如下:
图1到图2变化的像素相对集中,那么gif还需要储存全图的情况下,apng只需要储存很小一张图像就可以解决问题了。这种情况下apng的优化率会大于gif。
当然,我们会考虑将这两种differ方式结合起来。不过gif是牺牲了alpha通道做到的,所以已经很困难了。而apng则需要为每个像素再加一位来表示它是否用上一帧的,明显会增加新的数据,对于本来就是索引表的每个像素增加新的数据,到底好不好这可就不好说了.....反正apng并没有这么做。
4. 另外对于app来说,还需要考虑两种动图的解析性能成本——当然,本来文件结构就很相似,他们这方面成本自然无法比较。
因此总的来说,对于不带透明通道的动图,gif和apng彼此彼此不分伯仲,但是带透明通道的当然就不用话说了。
APNG vs MNG
mng又是啥,mng是png的兄弟格式,是为了覆盖所有的图片格式而诞生的。它和png类似,也是chunk性质的,不过这个就复杂很多很多了(http://www.libpng.org/pub/mng/spec/),基本没法详细讲解了。在mng里面,可以有png,jpg等多种单个图像,通过图层,变换,动画等各种方式来组成这个复杂的mng文件。
1. 和apng相比,mng就想对单层的静态图片多了一层封装结构一样,而它内部实际的图像数据储存块并没有创新,因此对于相同的图片,mng文件会大于apng。相比起来mng就想是一个psd一样是万能的封装,当然大了。
2. 由于可以通过图层和变化来实现不同帧的图像复用,因此在特定的动画场景下,mng的动态图像会小于apng,不过这种东西无法通过算法或者自动的方式换转得到,只能由图像生产者直接输出,因此就算遇到了适用情况(比如大部分表情包),是否有能力转换到较小的mng图像还是一个非常存疑的问题。
3. 对于app来说,再考虑解析成本的话,mng这样复杂的格式显然会大大增加解析性能消耗和内存。
因此在没有必要的情况下,几乎不太可能选择mng。
APNG vs WEBP
首先用apng和webp相比较似乎不太科学,毕竟apng和gif和mng对应的是png,是无损图像格式的动态化方案;而webp对应的是jpg,是有损图像的方案。就想png和jpg在互联网上各有各的长处相安无事一样,webp与apng同时存在并没有什么问题。不过既然要选优,当然也做一下对比比较好。
简单介绍一下webp,它是谷歌源自vp8视频编码格式拓展出来的图像格式,它的核心图像储存算法就是vp8编码了,动图的webp拓展的储存方式当然也就和vp8的视频无异(类似于webm)。不过因为是单纯的图像储存,所以实际文件结构并不想mng一样过于冗余繁琐。同时,作为静态图片的webp现在在互联网上的呼声是最高的,因此,作为高级版本的动态版webp,也会顺带一起支持。
1. 那么和apng相比,由于是类似于视频编码方式的无损或者有损压缩,确实比普通的lwxxx压缩方式高端很多,并且有类似于视频编码的differ帧计算技术,所以从实际各方测试效果表明,绝大部分情况下,webp的动态图像是小于apng的,并且越是复杂的图案和动态变化,这个优势越明显。
2. 另外由于谷歌的大力推广,webp的相关工具链的成熟度远大于apng,大概是webp>>apng>mng。因此对于图像向webp的转换,并没有太大的难度。
3. 另外app的解析成本的话,根据疼讯的测试,大概在普通png的5倍左右,实际占用内存和显示性能应该也会差。嗯可以理解,毕竟是一个非常复杂的储存结构了。
因此,总的来看webp确实是一个优于apng的方案,在原生支持的情况下,采用webp基本确认优于apng,不过现在的形势并不那么确定。
图片序列
事实上在app和web上,对于动态图像的处理并不是以上的方案,各种图片序列也是最常见的方案。
图片序列是储存在同一张图的多帧图像通过不断修改图像的锚点位置来实现动画(css),或者直接加载不同的图像。比如b站收藏按钮动画就是这样的一张图:
1. 这样储存的图像占用储存显然是最大的,但是对应换取的是最快的解析和渲染速度,占用内存也并不高。
2. 图像序列的第二个好处是可以很方便的进行速度控制和动画进度控制,并实现图像复用。对于各种粘手场景的动画操作(比如下拉刷新的动画),这是很有必要的。
3. 在app和web上,图片序列永远是最方便和最通用的方案,永远不会有各种奇怪的问题。
巧妙掠过的问题
刚才讲apng,mng和动态webp时,我巧妙掠过了一个最关键的问题,即各端兼容性问题,在这里我们再来看看吧。
APNG
apng现在主要是Mozilla在支持...它甚至不被png组织本身支持。因此它现在的支持性主要在ff上。
原生支持:Firefox Safari(>=8) Opera(旧版)
社区支持:apng-canvas实现在所有现代浏览器上支持 japng_android实现安卓 APNGKit实现iOS
MNG
mng是png组织官方的推荐格式,不过实际上由于它太复杂了,它在这三种格式中发展得最差。
原生支持:Firefox(旧版)
社区支持:没有,不过ios理论上可以直接引用官方c代码
WEBP
webp是谷歌主推的,因此基本上chrome系的浏览器都没问题。
原生支持:Chrome Opera(新版) Android(>=6)
社区支持:WebPJS实现在所有现代浏览器上支持 SDWebImage提供ios上兼容
结论部分
0. gif再见。
1. mng还是算了,再见。
2. webp有谷歌支持,可能会发展的很好,但是动画webp特性较新,支持性存疑。
3. apng有Mozilla支持,最近也打通了让苹果支持,因此也比较看好。压缩率可能比webp低,性能比webp高,向前兼容性好。
综上所述,我站APNG,通过社区支持也能做到最好的性能和兼容性的平衡。不过要我做产品,我还是选择gif和图片序列。