还在使用GIF?为何不了解一下APNG

前端优化

2018-11-12

# 简介

APNG(Animated Portable Network Graphics),基于PNG(Portable Network Graphics)规范的扩展动画文件格式。APNG文件是一种类似于GIF文件的动画格式,但是支持了GIF不支持的24-bit图像以及透明通道。另外,基于GIF生成的APNG尺寸往往小于GIF。因此,APNG是一种可以用来代替GIF的文件格式,因为你可以选择比GIF更好的效果或者选择比GIF更小的文件尺寸。 本文的主要目的是推荐前端同学将当前的GIF格式替换到APNG格式。如果你是前端同学,并且你已经了解APNG格式的优势,那么你可以将本文推荐给身边的前端朋友。如果你尚未了解APNG格式,建议你花5~10分钟时间读完本文。 本文结构如下,首先介绍常用的几种动画格式及其特点,接下来会介绍如何生成APNG格式以及其效果,最后是偏硬核的APNG技术细节介绍。不必担心,技术细节一样有趣。

# 集中动画格式的对比

目前最流行的动画格式是GIF格式,除此之外,本文提到的APNG格式,以及WebP格式都是比较常见的动画格式。本文建议使用的动画格式是APNG格式。

# 尺寸

相同图像效果下尺寸从小到大的顺序依次为:WebP < APNG < GIF 说明:理论上来说WebP的压缩率是最高的,但是经过实际测试发现如果同样是从GIF转换过来的图片格式,APNG的文件尺寸往往小于WebP的文件尺寸。

# 效果

从图像质量的维度来看,WebP = APNG > GIF。因为WebP和APNG都可以提供24-bit图像已经透明通道,因此这两种格式的动画的图像质量都要远远好于GIF格式。

# 性能

从加载时间的维度来看,WebP > APNG > GIF。由于APNG图片的第一帧是一张完整的PNG图片,因此WebP格式的首图像显示时间要小于APNG格式的首帧显示时间。另外,通过使用UC的开发者工具,Trace工具也可以直观的查看到不同格式的动画显示时间,CPU占用率。 以下视频显示了apng和webp在相同环境下的效果。

# 支持情况

GIF > APNG > WebP GIF毫无疑问是支持的最好的,全平台支持。 APNG目前在safari和最新版本的chrome for android上支持,android的系统webview尚未支持。 undefined WebP在iOS上尚未支持。 undefined 目前,安卓版的U4内核已经完整支持WebP格式和APNG格式的动画,对应的阿里系内应用也全面支持这两种格式的动画。U4内核团队不但会在内核中持续增加更多的功能,在稳定性,性能等各方面的表现也会做持续不断的优化。

# APNG实战

前面简要的介绍了APNG。接下来我们会通过实例,使用GIF文件生成APNG格式的文件进行比较。 压缩工具 本文选用了gif2apng作为压缩工具,版本是1.9,工作环境是ubuntu16。工具可以在github上通过关键字"gif2apng"检索并下载,使用方法如下:

gif2apng options anim.gif anim.png -z0:zlib压缩 -z1:7zip压缩(缺省) -z2:Zopfli压缩 -i##:7zip和Zopfil的循环次数(缺省为15)

# 实例

选择了某电商的三张gif图片做测试,原始图片如下: 图一 undefined 图二 undefined 图三 undefined 压缩命令如下:

例如使用Zopfil压缩方案,循环100次压缩gif3.gif文件,生成png3-z2-100.png

undefined 实验结果如下: 表1.png 实验结论: APNG格式的尺寸一定小于GIF,普遍可以节省15% ~ 30%的空间 Zopfil比7zip的压缩率更高,可以节省1%的空间 循环次数对压缩比影响小于算法 循环次数增加会导致压缩时间变长 压缩后的效果如下(下例使用Zopfil压缩,循环15次):

另外,不同的压缩方式,不同的压缩循环次数目前没有对图片的显示有明显的影响(包括CPU使用率,内存等),不过这个结论还需要继续观察。

# 兼容方案

前端同学在使用新技术开发业务的时候,最关心的一个问题就是是否有兼容方案。如果一项新技术没有兼容方案,则很难顺利的应用到业务中。那么,如果对于不支持APNG格式的平台,前端同学需要如何处理?回退到GIF动画么? 答案是不必。apng-canvas是一个JS版本的兼容方案。如果你的业务检测到平台不支持APNG格式时可以使用这个库做兼容方案。

# 如何检测你的应用是否支持APNG格式

示例代码

/*
 * apng-detect.js
 * 2010-06-13
 * By Eli Grey, http://eligrey.com
 *
 * Detects if a browser supports the APNG format and sets a
 * global `APNG` boolean indicating if the browser supports APNG.
 *
 * Public Domain.
 * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
 */
(function() {
  "use strict";
  var apngTest = new Image(),
  ctx = document.createElement("canvas").getContext("2d");
  apngTest.onload = function () {
    ctx.drawImage(apngTest, 0, 0);
    self.APNG = ( ctx.getImageData(0, 0, 1, 1).data[3] === 0 );
  };
  apngTest.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==";
  // frame 1 (skipped on apng-supporting browsers): [0, 0, 0, 255]
  // frame 2: [0, 0, 0, 0]
}());

APNG表示你的应用是否支持APNG格式。代码来自github,请检索apng-detect.js。原理,不支持APNG的应用只能绘制第一帧,支持APNG的应用可以绘制到第二帧,判断canvas的数据是否为第二帧数据即可以判断应用是否支持APNG。

# 兼容方案示例

在github上检索ang-canvas,获取JavaScript绘制APNG动画的能力。 示例代码

var img1 = document.getElementById("z1")
img1.src = "./resources/test.png"
img1.onload = function() {
  APNG.animateImage(img1);
}

图片加载成功后,调用APNG.animateImage绘制的img元素。 通过trace工具查看,使用兼容方案绘制APNG动画不会有明显的CPU占用率提升的现象。实际使用过程中也未发现有明显卡顿,掉帧等现象。另外,该JS库的尺寸为15K,因此当页面中原始GIF文件的总尺寸超过100K时,即使你的业务运行的平台不支持APNG解码,使用该JS兼容方案也能获得收益。

# 关于APNG的一些技术细节

前面章节介绍了APNG的优势(尺寸,效果等),下面章节主要是介绍APNG本身的一些技术细节,跳过后面的章节并不影响你使用APNG。

# PNG结构

一个标准的PNG格式由PNG签名(8 bytes)和多个PNG块构成。一个PNG块由4部分构成:块长度(4 bytes),块类型(4 bytes),块数据以及CRC校验(4 bytes)。 undefined 最简单的PNG格式由3种PNG块构成,IHDR(图像头)块,一个或多个IDAT(图像数据)块和IEND(图像结尾)块。 undefined

# APNG结构

PNG格式在设计之初就考虑到扩展性,解码器在解码PNG格式或基于PNG扩展的格式的文件时,只需要解码支持的PNG块,忽略尚未支持的PNG块。因此一个仅支持PNG格式的解码器解码APNG文件时,识别到APNG文件中的PNG签名,IHDR块,IDAT块,IEND块也可以将缺省图片解码出来。因此APNG格式是向后兼容的。 undefined

# acTL结构

IDAT块之前一定有acTL块 表2.png

# fcTL结构

IDAT块或fdAT块之前一定有fcTL块 缺省图片,如果存在fcTL块则一定出现在第一个IDAT块之前。不存在相对于acTL块的位置 缺省图片以外的第一帧,fcTL块一定会出现在全部IDAT块之后,fdAT块之前 其余帧,第N帧的fcTL块一定出现在第N-1帧的fdAT块之后,第N帧的fdAT块之前 表3.png

# GIF文件尺寸比较

APNG和GIF都是增量渲染,即仅渲染帧变化的区域,这样可以降低文件尺寸。那么为什么同样的动画文件,APNG尺寸小于GIF? 以下是相同的动画内容不同文件格式的数据解析,显示了每一帧在文件内所占用的尺寸: GIF文件解析结果 undefined APNG文件解析结果 undefined 结果对比 表4.png GIF文件的压缩方式导致它每一帧都会大于同等质量的APNG文件。另外,GIF每一帧的额外数据尺寸大约为200Bytes,而APNG每一帧的额外数据尺寸大约为40Bytes。因此,帧数越大GIF文件的尺寸也会越大。GIF动画压缩算法和APNG动画压缩算法我们可以另外找时间讨论。

# 参考文档

APNG Wiki (opens new window) APNG那些事 (opens new window) APNG规范 (opens new window) Animated PNG VS. Animated Webp VS. GIF battle Royale! (opens new window)