前言
我们知道,理想的网页应该在 1 秒内打开,而在页面的整体大小中,图片往往是所占比例最大的一部分(大约占到 60% 以上,更多了解请点击),也可以参照如下图所示。优化图片不仅可以加快页面显示,还能降低移动网络的流量费用。原图产生的 PNG、JPEG、GIF 和 SVG 图片一般都有很大的压缩余地。下文将重点介绍一款图片新格式:WebP,从而揭开它神秘的面纱。
解决方案:使用 WebP 优化图像
什么是Webp?
WebP是一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式,至于什么是有损压缩,什么是无损压缩,自己点进去看看
WebP的压缩的原理
第一步:宏块
与JPG相同的时,WebP也采用宏块进行压缩,典型的宏块由一个 16×16 的亮度像素(luma pixel)块和两个 8×8 的色度像素(chroma pixel)块组成。分块越小,预测越准,需要记录的信息也越多,一版来说,细节月丰富的地方,分块越细。相对不丰富的地方使用16x16分块。
第二步:预测
WebP最大的不同之处在于每个4x4的宏块中都有一个预测模型。(又名:过滤),PNG过滤用的比较多,它对每一行做同样的事,WebP过滤是针对每一个块。
VP8帧内预测常用的三种宏块:
- 4x4 亮度像素块
- 16x16 亮度像素块
- 8x8 色度像素块
编码器会将它们放在一个4x4的测试像素块填满,并确定哪一个生成了最接近原始块的值。这些用不同方法填满的块叫做”预测块”。
主要使用的预测方式有以下4种:
- H_PRED(Horiz prediction-水平预测)——像素块中每一列使用左边一列(col L)的数据填充
- V_PRED (vertical prediction-垂直预测)——像素块中每一行使用其上边一行(row A)的数据填充
- DC_PRED (DC prediction - DC 预测)——像素块中每个单元使用 row A 和 col L 的所有像素的平均值填充。
- True Motion (TrueMotion 预测)——一种超级先进的模式,我没找到原理,暂时还不懂。

image.png
对于4x4的亮度块,会有6种额外预测模式,类似于垂直预测与水平预测方式,他们可以从不同的方向去填充剩余色块。
第三步:DCT(离散余弦变换)
将预测部分的原图数据减去预测出来的数据,得到差值矩阵,最后对差值进行DCT。此步骤会生成一个频率系数矩阵,坐上的系数幅度最大,右下的最小,幅度值越小,频率越高。大部分图片信息都在左上区域,这一步的作用就是朱熬出图片的高频区域和低频区域。
第四步:量化
人眼对高频部分不敏感,这一步会将高频部分舍去。对上一步的频率系数表和量化表进行计算,将频率系数表和量化表按位相除,并四舍五入整数位,最终生成一个量化矩阵。
第五步:算法编码
WebP不同于JPEG,也可以说由于JPEG压缩的地方在于,WebP采用了算法编码压缩(Arithmetic encoding),JPEG采用的是霍夫曼编码(Huffman encoding),算法编码提供了优于霍夫曼编码5%-10%的压缩率。
WebP转换技术图片瘦身实践
一、Android系统版本对WebP的支持
Android 系统在 4.0 版本中添加入了 WebP 的支持,并在 4.2.1 版本中加强了它:
- 4.0+ (Ice Cream Sandwich): 基础的 WebP 支持
- 4.2.1+ (Jelly Beam MR1): 支持带透明度与无损的 WebP
Fresco 默认使用系统的 WebP 方案来加载它。
但同时,Fresco 能够让你在更老的版本中使用 WebP,所以如果你想要在 Android 2.3 版本的设备上使用 WebP, 你需要做的就是在工程中添加一个 webpsupport的依赖:
dependencies { // your app's other dependencies compile 'com.facebook.fresco:webpsupport:1.0.1'}
- 无损压缩的WebP比PNG至少压缩26%的体积,在相同的SSIM下有损压缩的WebP比JPEG压缩至少25-34%的体积;
- 无损WebP的支持的透明通道只占大约22%的字节,有损压缩支持RGB和透明度的压缩,通常可以压缩PNG的1/3文件大小
二、实践转换图片
实践出真知,为了得出准确的结论,将WebP技术应用到我们的58Android项目中,以下内容都为实践结论:
将PNG转换WebP的效果
将三种图片同时在手机上显示查看效果,图片类型如下:
- 原图
- 原图无损压缩(58%)
- 原图转WebP(有损压缩75%)
从上图可以看出三种图片从肉眼看是无差别的
PNG转WebP是可以控制有损压缩比例的,上图有损压缩75%,肉眼查看无差别,那其他的压缩比例呢?
接下来我们继续做实验查看:
三张图片进行对比
第一张为原图、第二张为使用tinypng在线压缩过的图片、第三张为WebP不同压缩比例的图片
-
无损压缩转换
-
有损压缩(75%)转换
-
无损压缩(50%)转换
-
无损压缩(0%)转换
三、数据分析
通过图片效果对比和上表数据分析,WebP的有损压缩75%是图片肉眼看是无差别的,文件体积减少也是较大的,是官方推荐方案
以上对比我们初步有了方案,再思考一个问题:
PNG经(tinypng)压缩是可以叠加压缩,同时图片体积也叠加减少的,那叠加压缩的图片在进行WebP转换是不是效果会更好呢?
带着问题我们做一个实验
1.先将PNG经过tinypng叠加压缩,查看效果
2.将每次叠加压缩后的图片转换WebP(有损压缩75%),查看效果
原图转换WebP
第一次压缩(叠加)后转换WebP
第二次压缩(叠加)后转换WebP
第三次压缩(叠加)后转换WebP
第四次压缩(叠加)后转换WebP
可以看出图片肉眼看是无差别的
我们在分析一下体积变化
结论:webp文体大小与图片压缩次数成正比,WebP的转换最好是用原图转换
GIF转换WebP效果对比
1、原GIF图
2、将原gif转换AnimationWebP
PNG(images with transparency/alpha)转换WebP效果对比
带有透明通道的图片转换效果对比
查看效果后产出结论
1、项目中的原图体积是39.6KB(之前是经过压缩了的图片),转换(75%)后的体积是43.0KB,反而增大了;2、不是所有的图片在推荐的有损转换75%的情况下体积会变小,尤其是有透明度通道的图片; 四、讲解一下Android studio 自带 WebP Tool
- 支持有损转换,默认推荐75%,同时支持无损转换;
- 可以跳过那些转换后比原是大小大的文件;
- 点9图是默认跳过,不支持转换的;
- 可以跳过有透明度通道的图片;
四、将项目中hybrid module 的drawable资源压缩
以上试验可以看到WebP转换技术可以使图片体积减小,如果我们将项目中的资源图片都替换成WebP是不是APK的体积会明显减小呢?
就以我们58主工程的hybrid module的drawable资源做实验
- 使用WebP tool 将所有资源转换,跳过含有透明度通道的图片
- 查看APK大小
效果分析:1、仅hybird库就可以减少将近1MB的大小,全部替换更客观; 2、但因为WebP格式存在机型适配问题,不能将全部图片替换.
WebP对图片的体积减少真的是个利器,那么内存方面的影响呢,我们项目中图片框架是Fresco,同时Fresco对WebP也做了很好的支持,接下来使用Fresco加载WebP查看内存的占用。
五、Fresco加载WebP在项目实践中的内存占用
项目中往往引导图都是较大的图片资源,使用引导图作为试验对象,查看内存情况,同时可以得出是否有优化空间。
1、项目中找一个引导图做实践
先来看PNG和WebP图片引导图的显示效果
PNG图片,原生控件ImageView加载显示
WebP图片,Fresco控件加载WebP显示
显示效果一致,肉眼看无差别 #引导图PNG转换为WebP操作数据对比
图片体积减少40% 2、引导图PNG和WebP内存占用对比
为了更好的显示对比效果,我做了一个显示数量扩大的试验,具体操作步骤如下:
先使用PNG图片为引导图
- 使用一个引导框(Dialog)为例,有一个引导图,如上图显示;
- 将引导图的PNG图片资源用原生ImageView加载,在未弹起引导框时记录初始状态内存量(A);
- 弹起引导框->关闭引导框->再弹起引导框->关闭引导框,每个引导框对象都是new 出来的,如此重复1000次后,记录执行1000次引导操作后内存量(B);
- 强制执行GC操作,执行多次,在内存平稳时记录执行GC后内存量©;
- 计算执行GC后比初始状态增加内存量(C-A)。
将PNG图片转换为WebP后使用Fresco加载,重复PNG图片引导图的操作步骤,然后进行数据对比
3、将结果纪录并对比
结论:1、5.0以上系统,由于内存管理的优化,所以对于5.0以上的系统 Fresco将Bitmap缓存直接放到了Java Heap中,5.0以下系统,图片不存储在Java heap,而是存储在ashmem;2、Android 原生ImageView的PNG显示引导图增大了native heap内存;3、使用原生ImageView 加载图片内存增大要比使用Fresco大;4、强制执行GC只会释放Java Heap,对Native Heap 无影响; 七、Android Profier的使用简介
如上图所示,内存分析器的默认视图包括以下内容:
-
① 强制执行垃圾收集事件的按钮。
-
② 捕获堆转储的按钮。
-
③ 记录内存分配的按钮。
-
④ 放大时间线的按钮。
-
⑤ 跳转到实时内存数据的按钮。
-
⑥ 内存使用时间表,其中包括以下内容:
-
- 每个内存类别使用多少内存的堆栈图,如左边的y轴和顶部的颜色键所示。
- 虚线表示已分配对象的数量,如右侧y轴所示。
- 每个垃圾收集事件的图标。
在classes列表中,您可以看到以下信息:
- Heap Count: 堆中的实例数。
- Shallow Size: 此堆中所有实例的总大小(以字节为单位)。
- Retained Size: 这个类的所有实例(以字节为单位)保留的内存总大小。
在类列表的顶部,可以使用左下拉列表在以下堆转储之间切换
- Default heap: 当系统没有指定堆时。
- App heap: 应用程序分配内存的主堆。
- Image heap: 系统引导映像,包含在引导期间预加载的类。这里的分配保证永远不会移动或离开。
- Zygote heap: Android系统中分发应用程序进程的写时复制堆
六、项目使用WebP格式文件的规范
- 使用推荐转换方案,75%有损压缩;
- Fresco对WebP的使用做了支持,相当于扩展了一种图片类型,API的使用和PNG、JPEG、GIF无差别;
- 对于大图显示建议使用Fresco加载,使用WebP格式降低文件体积
总结
WebP的压缩优于其他图片,主要得益于起继承自VP8的帧内预测技术,相比于JPEG对图像原值进行编码来说,WebP编码的是预测值和原值的差值,这也是WebP体积更小的主要原因,最后,WebP使用了更优秀的算法编码。有关Android性能优化的更多学习~获
这个WebP的压缩过程用,一张图可以囊括表述:
当然以上主要是针对WebP的有损压缩(lossy WebP)来进行的原理讲解,无损压缩的逻辑与其完全不同,不过我们提高性能,主要也是采用的有损WebP。
希望以上内容,对大家了解WebP的原理有一定的帮助,能让大家更好的去使用WebP。