1.WebP 图片在安卓上的使用(https://developer.android.com/studio/write/convert-webp.html) WebP 图片格式 WebP 是 Google 在 2010 推出的一种图片格式,此图片格式可以比 jpeg 有更小的体积,同时支持无损压缩和透明。关于 WebP 格式的介绍参见 http://www.jonathanklein.net/2013/02/a-comprehensive-guide-to-webp.html。 WebP 格式,Google 开发的一种旨在加快图片加载速度的图片格式。Android 4.0(API 级别 14)及更高版本支持有损 WebP 图像,Android 4.3(API 级别 18)及更高版本支持无损和透明的 WebP 图像。 2010 年谷歌推迟的图片格式, 专门用来在 web 中使用, 压缩率只有 jpg 的 2/3 或者更低; 第一个版本的 webp 图片格式是有损的, 新版本中 webp 图片是无损的。 相对于 png 图片, webp 比 png 小了 45%, 但是缺点是你压缩的时候需要的时间较长; 问题描述 Android 原生支持的图片格式有 JPEG,PNG,GIF,BMP 和 WebP 五种。但是在 Android 应用开发中能够使用的编解码格式只有其中三种:JPEG、PNG、WebP,图片格式可以通过查看 Bitmap 类的 CompressFormat 枚举值来确定。WebP 格式是从 Android4.0 版本开始支持,对 Android4.0 及以上版本可以直接用 BitmapFactory 来实现解码,对 Android4.0 以下版本不支持。 使用 BitmapFactory 对图片解码的示例代码如下,options 是 BitmapFactory.Options 对象。BitmapFactory 会自动判断图片格式,如果解码成功会返回一个有效的 Bitmap 对象,如果解码失败会返回 null。 Bitmap bitmap = BitmapFactory.decodeStream(imageStream, null, options); 正常来说,对 Android4.0 及以上版本通过上述代码解码 WebP 格式应该能够返回有效的 Bitmap 对象,然后实际使用过程中发现,有些 WebP 格式图片在 Android4.0 以上机型上无法通过 BitmapFactory 来解码,此外有个别机型虽然也是 Android4.0 以上版本,但所有 WebP 格式图片都无法解析。 再附上一个第三方解决方案(https://github.com/alexey-pelykh/webp-android-backport/tree/master/webp-android-backport-library) /** * Specifies the known formats a bitmap can be compressed into */ public enum CompressFormat { JPEG (0), PNG (1), WEBP (2); CompressFormat(int nativeInt) { this.nativeInt = nativeInt; } final int nativeInt; } 问题原因 从官方文档中可以看到在 Android4.0 到 Android4.2.1 之间的版本不支持无损压缩和透明格式的 WebP 图片的编解码。所以如果从要解析的 WebP 图片中包含无损压缩或透明格式,且当前是 Android4.0 到 Android4.2.1 之间的系统,则 BitmapFactory 解码时就会出错。 此外,个别 Android 机型虽然是 Android4.0 及以上的版本,但是在原生 ROM 基础上去掉了 WebP 功能,目前发现的只有 NokiaXL,它是 Android4.1 的版本,但不支持任何 WebP 格式的编解码。 解决方法 Android SDK 中并没有任何 api 可以判断当前设备是否支持 WebP 格式,也没有办法在解码前判断一张 WebP 格式图片中是否包含无损压缩和透明格式。只能通过 BitmapFactory.decodeStream 的结果来判断是否解码成功。因此,只能先尝试用 BitmapFactory 来解码,如果解码失败,再尝试用其他方法(通过 google 提供的 libwebp)。目前来看 Android4.2 及以上版本中应该都已经支持所有的 WebP 格式图片的解码,因此,也可以统一从 Android4.2 版本开始用 BitmapFactory 来对 WebP 格式图片编解码,对 Android4.2 以下版本用其他方式实现。 然而,对于动态 WebP,目前只能找到 facebook 的开源库 Fresco 对其支持,不过 Fresco 最低仅支持 API 9,且引用的相关库较多。 https://www.fresco-cn.org/ 2.SVG(Scalable Vector Graphics)图的使用 “清晰”和 “体积” 的矛盾与麻烦 面对 android 的各种 dpi 某事,想要所有设备上的图片都能有最清晰的效果,就意味着每种 dpi 模式都必须提供一份对应尺寸的资源,除非你不在乎安装包的体积有多大,所以这显然是不可能去做的。 在过去的几年里 andorid 从 mdpi 发展到 xxxhdpi,每当 APP 想让相同的图片在更清晰的屏幕上显示我们想要的效果时,我们总要重新提供一份体积更大的高清 png 并且删掉可能不太多使用的小分辨率图片。 只保留一种分辨率图片的方法确实比所有 dpi 都来一份体积要小一点,然后只是用一份资源还需要承担的负面效果则是当向其他 dpi 模式 scale 时,图片也会变得模糊,并且你还要决定自己什么时候该更换上更大分辨率的图片了。 矢量图 SVG 位图自身特点导致了高清资源同安装包体积之间的矛盾。这方面矢量图存在明显的优势,它可以在表达清晰图片的同时,不增加文件体积。而且只要你不重新设计图片,就用不着再去适配高 dpi 模式,矢量图什么分辨率都可以自适应。 我们认为 SVG 是比较合适的矢量化资源方案,因为它相比目前 android 上的一些矢量化方案更成熟、周边工具支持更好。像 VectorDrawable、ttf 这样的方案总有这不尽人意的地方,对于 UI 同学来说这两个模式也不太好操作,不能轻易生成的资源会牺牲大家的工作效率是明显得不偿失的。(另外,VectorDrawable 经过我们测试发现性能并不理想,这受限于他的实现方法。) 使用 SVG 图面临的几个问题 1) 性能问题 理论上讲,SVG 的效率可能会不如 PNG 好,这是因为它需要运行时的计算和对应平台的渲染绘制。而且对于 PNG 来说的另一优势是在开启硬件加速的设备上,绘制 Bitmap 一个非常快速的过程。可以想象,让 SVG 不比 PNG 慢将是一件很有挑战的事情。 2) 开发者的使用成本问题 SVG 并不是 android 支持的标准资源格式,android 资源框架自然不可能天然支持 SVG 的资源加载,而修改框架和提供支持很可能意味着会增加后面使用 SVG 的开发同学的学习成本和使用成本。因此必须要考虑如何即可以用 SVG 但又不增加开发负担。 3) 设计师的要求 SVG 图的制作,对设计师的要求也很高,因为 SVG 涉及到 CSS 编码,不光是要求设计师掌握 PS 就可以了。好在现在有个比较好的开源 SVG 库 http://www.iconfont.cn/plus/collections/index?type=2&spm=a313x.7781069.1998910419.5.hOR7v0 什么样的图适用 SVG? 矢量图适用于简单的图标。Material 图标是适合在应用中用作矢量图的图像类型的一个好例子。相比之下,许多应用的启动图标包含许多细节,因此更适合用作光栅图像。 与对应的光栅图像相比,矢量图首次加载时可能消耗更多的 CPU 资源。之后,二者的内存使用率和性能则不相上下。我们建议您将矢量图像限制为最大 200 x 200 dp;否则,绘制它可能需要耗费很长的时间。 尽管矢量图确实支持一种或多种颜色,但在很多情况下,最好将图标设置为黑色 (android:fillColor="#FF000000")。通过此方法,您可以为布局中放置的矢量图添加 tint 属性,图标颜色将随之变为 tint 颜色。如果图标颜色不是黑色,图标颜色可能反而与 tint 颜色较为搭配。 为图片资源着色 利用 Android 5.0(API 级别 21)及更高版本,您可为位图以及定义为 Alpha 蒙版的点九图着色。 您可使用颜色资源或分解为颜色资源(例如 ?android:attr/colorPrimary)的主题属性为其着色。 通常,您只有一次机会创建这些资产并自动为其上色以符合您的主题。 您可利用 setTint() 方法为 BitmapDrawable 或 NinePatchDrawable 对象着色。您也可以利用 android:tint 以及 android:tintMode 属性设置您的布局中的着色颜色和模式。 矢量图向后兼容性解决方案 下表归纳了可用于实现向后兼容性的两种技术: 技术 APK 中的可绘制资源 XML VectorDrawable 元素 版本 版本号标志 应用代码 PNG 生成 矢量和光栅 支持的子集 SVG:适用于 Gradle 的 Android 插件 1.5.0 或更高版本 PSD:Android Studio 2.2 或更高版本 默认 支持的各种编码技术 支持库 23.2 或更高版本 矢量 完全支持 适用于 Gradle 的 Android 插件 2.0 或更高版本 需要支持库声明 支持的编码技术子集 对于 Android 5.0(API 级别 21)及更高版本,Vector Asset Studio 支持所有 VectorDrawable 元素。为向后兼容 Android 4.4(API 级别 20)及更低版本,Vector Asset Studio 支持以下 XML 元素: <vector> android:width android:height android:viewportWidth android:viewportHeight android:alpha <group> android:rotation android:pivotX android:pivotY android:scaleX android:scaleY android:translateX android:translateY <path> android:pathData android:fillColor android:strokeColor android:strokeWidth android:strokeAlpha android:fillAlpha android:strokeLineCap android:strokeLineJoin android:strokeMiterLimit SVG 图文件说明 <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path d="M250 150 L150 350 L350 350 Z" /> 10. </svg> 上面有一个 path 标签,里面用到了 M 和 Z 指令,M 就相当于 android Path 里的 moveTo(),Z 则相当于 Path 里的 close(); 我们先看下 SVG 里关于 path 有哪些指令: M = moveto 相当于 android Path 里的 moveTo(), 用于移动起始点 L = lineto 相当于 android Path 里的 lineTo(),用于画线 H = horizontal lineto 用于画水平线 V = vertical lineto 用于画竖直线 C = curveto 相当于 cubicTo(), 三次贝塞尔曲线 S = smooth curveto 同样三次贝塞尔曲线,更平滑 Q = quadratic Belzier curve quadTo(),二次贝塞尔曲线 T = smooth quadratic Belzier curveto 同样二次贝塞尔曲线,更平滑 A = elliptical Arc 相当于 arcTo(),用于画弧 10. Z = closepath 相当于 closeTo(), 关闭 path 支持库 此技术需要 Android 支持库 23.2 或更高版本、适用于 Gradle 的 Android 插件 2.0 或更高版本,且仅使用矢量图。利用支持库中的 VectorDrawableCompat 类,可实现在 Android 2.1(API 级别 7)及更高版本中支持 VectorDrawable。 在使用 Vector Asset Studio 之前,您必须向 build.gradle 文件添加一条声明: android { defaultConfig { vectorDrawables.useSupportLibrary = true } } dependencies { compile 'com.android.support:appcompat-v7:23.2.0' } 您还必须使用与支持库兼容的编码技术,例如对矢量图使用 app:srcCompat 属性,而不是 android:src 属性。