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,且引用的相关库较多。
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 元素:
<group>
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
属性。