AVIF图片格式调研

1,961 阅读12分钟

1、为什么要做这个调研

包大小是衡量应用性能的重要指标之一。

然而,绝大部分低垂的果实已经被采摘,剩下的简单而又行之有效的方法,已经不多了。

如果我们可以通过一些更加先进的图片格式来压缩图片,那么,即使保守估计,获得1M左右的大小收益还是有希望的。

Google已经在Android 12中原生支持AVIF。据我所知,各大浏览器也在1年前陆续加入了对AVIF的支持。

下面就让我们一起看看,AVIF到底用到了哪些黑科技,相比于其他图片格式,又有什么过人之处吧~

2、不同的图片格式,各自都用到了哪些黑科技

常见的图片格式,按照发展顺序,包括JPEG、PNG-8、PNG-24、PNG-32、WEBP、AVIF。

当然,其中还包括了GIF、SVG、HEIC等。但是GIF只支持256色,主要应用于动图。SVG则是矢量图。HEIC又是苹果专有。他们都有各自的特殊性,所以这里暂时不参与讨论。

所谓tinyPNG,其算法的核心就是把PNG-24压缩为PNG-8,并且移除图像文件不必要的元数据,进一步压缩体积。

PNG-8只支持256色,与GIF相同,并且只有1bit的透明度通道。也就是说,PNG-8只支持全透明或不透明。

PNG-24支持多达1600w色,与JPEG相同。PNG-32还多了8bit的透明度通道,因此支持半透明。更重要的是,PNG-24是无损压缩,这对于需要保存原始图片的场景十分有用,但是对于app意义不大。

说回AVIF。某种意义上说,AVIF就是AV1。AVIF是根据AV1视频编码技术来的,用它来生成图片。

所以,有人戏称他是AV1的边角料。可就是这么个边角料,都用了很多黑科技。那AV1又是什么?

AV1(AOMedia Video 1)是开放媒体联盟(AOMedia)开发的新一代视频编码格式,这个联盟有很多巨头(Google,Apple,Adobe...)参加,AV1的目的是为了取代其前身VP9。

总之,AV1是目前开放出来的比较牛逼的编解码格式。很多流媒体运营商都已经早早的支持了AV1格式。

AV1的编码过程,和Webp几个主要核心的步骤是差不多的,分割,预测,变换,量化,熵编码,不同的是,做了一些新的特性和很多高级的优化。

主要是使用了很多的机器学习算法,它使得 AV1 能做出很多快速的决定,比如对搜寻方块划分的类型。

你可能不知道,JPEG图片格式竟诞生于《花花公子》一张美女(果)照。

在2020年的情人节,Netflix选择公开AVIF作为他们使用的下一代图片压缩技术。这距离JPEG标准的通过已经过去了整整28年。

如今,JPEG仍在被大范围使用。

看到这里,如果对原理不感兴趣的同学,可以直接看第三章了。

具体的原理,大家可以参考这篇文章,这里就不搬运了。

3、与其他图片格式相比,AVIF的效果如何

Google提供了一个APP,可以帮助我们非常直观的了解不同的图片格式之间的差距,包括文件大小和显示效果。点我传送

图片的质量是一个十分主观的概念,并不像解码时间,只需要一个时间数值就能表征区别。在这里,我选择通过以下几个个人认为较为经典的场景,看看AVIF相比其他图片的优势。

当然,如果我们想要专业的指标来评估两张图片的相似性也是可行的。感兴趣的同学可以参考DSSIM

这个计算方式能够以近似人眼视觉的标准去评估两张图片的相似度,由此我们就能确定压缩后的图片和原图的差异有多大。我们可以合理的认为,差异越小则图片质量越高。

3.1 场景一:当图片存在大量低频和高频部分时,能否在压缩后较好地保留细节 点我传送

image.png

大小相近的webp和avif(22.1kb对比18.2kb),avif在细节上的表现完胜webp。在这个大小下,webp的颜色已模糊成一团。

webp至少需要到达43kb才能有和avif相近的效果,而jepg则需要74.4kb。

3.2 场景二:图片中存在大量的纯色,整体颜色的数量较少,但是存在锋利的边缘,压缩后是否会模糊 点我传送

在这种case下,avif仍然有优势,但是优势不再明显。因为图片本身的色彩就不多,因此png-8之类的有损压缩,就可以很好地处理这类场景。

但是,减少颜色会导致图片的边缘产生杂色,下面这张图中,绿色衣服的边缘就产生了明显的紫边。

image.png

事实上,你的APP存在大量的icon都是这类场景。我们考虑使用矢量图SVG来替代有损压缩的PNG-8,也许是更好的选择。

3.3 场景三:图片中存在大量渐变色时,压缩后是否会形成明显的色块 点我传送

前面提到的压缩色彩空间,对于图片中颜色较少的场景是适用的。但是,如果图片存在大量的渐变色时,压缩色彩空间可能会导致明显的色块出现。

在这个例子中,当avif与webp的大小均为12.5kb左右时,avif仍能够保持一定的清晰度,而webp已经出现了明显的色块。webp达到同样的可接受的图片质量,需要的图片体积是avif的2倍左右。

image.png

4、在你的项目中落地AVIF可行吗

虽然AVIF在压缩率方面,对比传统的图片格式有着明显的优势,但是要把它应用到工程中,还需要考虑很多方面的情况。

4.1准备工作

4.1.1 怎么在MAC上查看AVIF

我使用的MacOS 12.0.1原生并不支持AVIF。据说2022年6月22日苹果会发布支持AVIF的Ventura Beta 1版本。但是至少现在,我们还需要安装一些软件才能查看avif的图片。

我选择的是AVIFQuickLook这个软件。感兴趣的同学可以通过传送门自行下载安装

4.1.2 怎么转换得到AVIF图片

首先,很遗憾的是,Photoshop并不支持AVIF。支持AVIF的呼声从2020年9月左右开始,但是一年过去了,PS官方仍然没有任何支持AVIF的迹象,也没有公布相关支持的计划。

我们可以利用github上的一个plugin,使PS支持AVIF。我是传送门

对于RD平时测试的话,我们一般不会安装PS。下面列举了一些网站,可以直接转换图片格式

  1. squoosh.app/
  2. avif.io/
  3. www.aconvert.com/cn/image/pn…

4.2升级Glide以支持AVIF的代价

尽管Android 12原生支持AVIF的decode,但这对我们意义并不大,Android 12仅仅是小部分机器。

Glide在4.13.0中加入了对AVIF的支持,最新版本为4.13.2。但是为支持AVIF,需要引入:

implementation "com.github.bumptech.glide:avif-integration:4.13.2"

这会使得apk体积增大0.4-0.5M左右(原始so的大小分别为645K(32位)和765K(64位))。

4.3 Glide的解码速度

解码速度受到图片本身的大小和机器性能的影响。而图片能够显示在屏幕上,需要经过至少IO和解码两个步骤。这里把这两部分时间分开计算。

使用的测试代码如下:

    private fun decode(fileName: String) {
        val data: ByteArray
        
        // IO的速度
        val ioCost = measureTimeMillis { 
            data = assets.open(fileName).readBytes()
        }
        // 解码的速度
        val decodeCost = measureTimeMillis {
            val futureTarget = Glide.with(this)
                .asBitmap()
                .load(data)
                .submit()
            try {
                val bitmap = futureTarget.get()
                bitmap.recycle()
            } catch (e: Throwable) {
                Log.d("denny", Log.getStackTraceString(e))
            }
        }
        Log.d("denny", "decode $fileName ioCost $ioCost decodeCost $decodeCost")
    }

使用的测试图片如下,分辨率均为1920*1080:

image.png

上图中,-acceptable是指图片质量近似的3张不同格式的图片进行对比,而-samesize则是大小相近但图片格式不同的图片进行对比。

测试结果中发现,IO的耗时通常都很短,尽管有波动,但基本都在1ms之内,至多不超过3ms,因此不再额外展示了。

下表仅显示decode耗时。同一段代码运行100次,取平均值。每次decode完成的图片会进行recycle,以避免资源复用的情况。以下时间为平均值,单位ms。

机型jpeg-acceptablewebp-acceptableavif-acceptablejpeg-samesize
Redmi K40 (Android 12)14153312
OPPO Reno10 (Android 11)24224522
Honor 8(Android 7)585615654
荣耀畅玩4x电信版(Android 4.4.4)8536030682

通过上面的表格我们可以得出一些结论:

  1. jpeg和webp的解码时间近似,差距不大。
  2. avif的解码时间明显更长一些,是jpeg和webp的2倍以上。
  3. avif的解码时间还受到机器的影响,相对老旧的机器需要更长的解码时间,猜测这可能与DSP硬解码处理模块之类的有关。
  4. 大小不同的两张jpeg(差距3-4倍),解码时间差距不大。说明jpeg文件大小与解码时间的相关性不强。
  5. webp在5.0以下的兼容性并不好,测试结果符合网上可查询到的结论。

换成下面800*600分辨率的图片,结果会有什么不一样吗

image.png

机型png-68colorwebp-68coloravif-acceptable
Redmi K40 (Android 12)3624
OPPO Reno10 (Android 11)4526
Honor 8(Android 7)71378
荣耀畅玩4x电信版(Android 4.4.4)2343142

我们发现,换了一张图片之后:

  1. avif的解码时间与png/webp之间的差距明显变大了。这说明图片本身对解码时间也有着很大的影响。压缩率越高的图片,需要更长的解码时间。我们也需要在压缩率和解码时间寻求平衡。

4.4 兼容性问题

  1. 从上一章的时间测试中不难发现,AVIF在不同设备上的解码时间有很大的区别,与图片本身的压缩率也有很大关联。尤其在Android 4.4这样的老旧设备上能否兼容,还需要更多的测试。
  2. 在Github上,有关于AVIF解码时间不稳定的相关反馈:传送门
  3. Android Studio似乎无法识别AVIF,因此测试的时候都是把图片放在assets下。

4.5 小结

尽管现有的测试数据并不是很多,但仍然可以初步得出结论,AVIF在兼容性上仍旧存在一定的问题,在解码速度上的劣势也较为明显。

在一些复杂的大图,且对加载时间不敏感的场景下,或许可以考虑使用avif来替代当前的tinyPNG。但是还要注意引入avif导致的包大小体积增加的问题,和低端机型上解码时间过长的问题。

5、引申话题:常见图片格式对比

5.1 JPEG

优点:体积比PNG24小,打开速度比PNG24快,能展示1600万种颜色。

缺点:有损压缩

适用区域:适合需要高保真展示的图片。色彩丰富的大图片

不适用区域:ICON类的小标签

5.2 PNG-8/PNG-24/PNG-32

PNG8用的是索引颜色编码方式,如果不是GIF支持动画其实PNG8完全可以胜过GIF。但是如果是同样的图片下,PNG8的更小。PNG8有1位的布尔透明通道(要么完全透明,要么完全不透明)。

PNG32用的就是Alpha透明通道,就是有8位(256阶)的布尔透明通道(所谓半透明),它也有1600万种颜色而且是无损压缩。与JPEG相比,PNG-24的体积约是JPEG的5倍,因此PNG-24不能替代JPEG。

相比于JPEG,PNG更适合ICON这类线条分明的图片。

适用区域:尺寸小的,色彩不丰富的图片最好就用PNG8。有半透明需求的就用PNG24,而且如果改图片需要频繁下载保存的最好就用PNG24因为它是无损压缩。

不适用区域:如果是特别大的而且需要展现多色彩的图片不适用于PNG8。对图片大小有要求的就最好不要用PNG24。

5.3 WEBP

webp支持有损和无损压缩,也能够支持动图。相同质量的图片下,webp的图片体积比JPG和PNG小30%-40%左右。

美中不足的是,WebP格式图像的编码时间“比JPEG格式图像长8倍”,而且目前安卓5.0以下版本兼容有时候有问题,且在低端手机解析webp图片的时候cpu的使用率将在20%-36%之间波动。

5.4 AVIF

最高的压缩率与最长的解码时间,兼容性尚不完善。

6、引申话题:你有多少无用的图片资源可以删除

运行Unused resources Lint

可以得到一份无用资源的列表。

当然,上述只是简单测试。具体资源是否可以移除,还需要一些测试。

7、附录:参考资料

  1. zhuanlan.zhihu.com/p/384722033
  2. juejin.cn/post/687074…
  3. juejin.cn/post/710678…
  4. juejin.cn/post/684490…
  5. github.com/bumptech/gl…