VectorDrawable的工作原理

来源:互联网 发布:追魂呼软件 编辑:程序博客网 时间:2024/05/12 15:37

转载请注明出处:http://www.jianshu.com/p/c37e119faa55

本篇文章翻译自谷歌出的优化视频里面的光头佬(Colt McAnlis),原文地址需翻墙, 以下正文:

我们已经讨论了Android世界里两种应用最广泛的图片格式(JPG&PNG)了,不放值得注意的是,实际上还有一些压缩级别是这两种格式算法无法达到的。说到这,我们得先停止对图片概念的想象,多了解一点算法。

栅格化图片

通常来讲,图片是一堆排列在一个二维平面的像素点,它代表图片本身的颜色。直白点说,就是一个像素点是一组颜色标量混合在一起,组成一个颜色,例如RGB。当我从远处看,像素间边缘融合在一起,最后呈现出平滑的颜色。这种类型的图片就叫”栅格化”图片。一般这些图片数据都被栅格化成一个2D图片,这也是我们最终看到的。

栅格化图片的核心是,它在没压缩情况下体积的增长是线性的。图片面积越大,像素就越多。像素越多,数据量就越大。数据量大会导致文件膨胀。比如你在手机上拍一张两百万像素的图片,这图片未压缩的话会达到~6M。

我们之前已经提到,压缩栅格化图片,跟图片本身的相似程度有关。图片有越多同样的颜色,越容易压缩。特殊颜色越多,就越难。这样导致的结果是,一张树木或草丛图会比一张纯白色图片压缩得更差。

例如,下面这张白色背景的红色实心圆,尽管它非常的简单,但也得压缩文件里的所有栅格化像素。

这对于Android工程师更是一个难题,因为它得支持mdip,hdpi, xhdpi, xxhdpi, xxhdpi 和xxxhdpi不同屏幕密度的屏幕,这意味同样图片在APK里需要保存多种大小。保存上面三张图片会使用户多下载55K数据,尽管有Multiple APKS这种黑科技,还是会保存一些重复的图片。

矢量图

如果,我们不是用栅格化像素来生成图片,而是用描述性语言呢?我们同样可以用绘图操作命令来绘制上图。

这是矢量图形背后的概念。与栅格化图片不同,这种图片格式包含了绘制到屏幕上的各种不同视觉属性。(总的来说这个过程叫做光栅化)。将所有命令合并到一起执行,最终会生成一个光栅图形。

重要的一点是:

一张矢量图可以生成所有分辨率的栅格化图片,且矢量图的文件大小不变。

也就是说,无论是 16×16 分辨率的还是 8092×8092 分辨率,一个矢量文件就能搞定。

SVG(可缩放矢量图形)文件格式

矢量图最广泛的实现方式是SVG,它在文件里定义了一堆绘图操作,最终生成的图片可以跨不同的平台,包括web和图形编辑器。下图是一个SVG文件,和栅格化后的样子。

当然,SVG也有一个广为人知的缺点,就是它通常都很臃肿。随着标准的发展,它必须增加新的绘图模式,混合模式,对传统业务的支持,以及更冗长的语法来描述视觉需求。

同时,SVG使用的是XML语法,在大多数实现中,也要符合人类的阅读习惯。这意味着,复杂的数字如”43.00102302”将替换成11个字节的字符串,而不是4个字节的浮点数。(尽管大多数web工程师会开启GZIP压缩SVG文件,但这与二进制文件还是没法相比的)。

Android的VectorDrawable

这也是为什么Android不对SVG提供原生支持的原因:Android对文件大小很敏感。支持SVG的所有功能将允许非常大的和复杂的文件被创建,这并不是我们想要的。

因此,Android自己定义了一种矢量格式叫做VectorDrawable。它的工作原理和SVG很像,但使用了部分更小的绘制属性。绘制过程是一样的:加载一个VD文件,然后App把它栅格化成一个Bitmap。Boom~(嘭~)

看,我画了一个安卓!

虽然VD文件也使用XML当作它们的格式,但它们最后会变编译成一个二进制序列化格式放到APK里,以减少它们的大小。

这样的话节省空间就简单了,使用VectorDrawable生成的图片替代原来的多张PNG图片,就可以节省很多空间。

使用VectorDrawable的另外一个好处是,它们还可以定义动画。如果你用PNG文件来做动画,那么你通常得把动画的每一帧都用png文件保存起来,它们看起来像这样:

而用VectorDrawable,你可以定义同样动画,但完全由xml生成,这会明显减少文件大小。

这不是银弹

虽然矢量格式在文件大小很有优势,但Android在使用时还是需要注意一些点。

越小越好

在Android系统上,将VectorDrawable转成一个Bitmap这个栅格化过程是由cpu处理的。因此,创建一张图片所需要的时间和图形本身的分辨率/尺寸大小,是呈线性关系的。比如,栅格化一个16x16像素的三角形,可能只需要处理8-12个像素。而处理同样质感的1024x1024像素的图片,可能要处理超过10万个像素,这显然需要更多的处理时间。

因此,当你的图片很大时,这将成为你需要权衡的点,因为此时加载这张图片的时间很长,再使用VectorDrawable意义就不大了。

Tip: VectorDrawable最好用于较小的图片

越简单越好

矢量图有一个局限是,它只能代表一个固定类型的图片质量。也就是说,矢量图往往会比较简单,只使用一组原生类型来定义怎么在屏幕上生成颜色。你图片越复杂,你的文件加载时间也会更长。

总的来说,使用VD时,最好先确保你的图片是一些简单的图形,这对一些图标或者ui控件就很有用。

Tip: VectorDrawable最好用于简单的图片

压缩

矢量格式的强大之处在于,只需很少的文件存储空间,却展示了非常大的内容。这个概念远不止适用于移动&Web框架。

如果你曾经好奇过DemoScene是如何将内容保存在这么小格式里的,其实过程很相似。这些图像是他们用数学算法产生的,2d和3d都可以用这种方式生成。werkkzeug是DemoScene里最著名的工具之一,尽管Substance已经被游戏码农使用了十几年。

古话说得好:”遇到难题时,用数学解决。

PS:由于文人水平有限,如有翻译得不好的地方,请留言讨论。

0 0