2014年4月20日

Android 实现模糊效果的一些笔记

不知从 ios 的那个版本起有了毛玻璃效果,于是这东西就成了 Android UI 设计师们爱用的效果之一。实现这个效果,技术的核心是对图像的模糊处理。

当然,技术上需要做到什么程度,取决于要实现的效果如何。如果需要模糊的对象是固定的,而且是整个图像一起模糊掉,那么最简单的办法还是在开发阶段就计算好模糊的图片——photoshop 的滤镜能达到的效果永远比工程师重复发明轮子在用户手机上算要来的好。然后把这模糊图放在清晰图的上面,通过控制模糊图 ImageView 的透明度来实现渐变毛玻璃效果。在布局不是特别复杂的情况下,这样做的效率还可以接受(实在想优化的话就自己在 Canvas 上画吧)。

如果需要在手机端计算模糊图,那么这篇文章这篇文章是很好的补习资料,常见的 Box blur 和 Gaussian blur 的原理讲的很清楚。实际上,Gaussian blur 因为涉及的基本都是浮点计算,执行时间是 Box blur 的数倍。以 note2 为例,自行计算一张 radius=16 的 720x1280 的 Gaussian blur 图片,Java 版本需要约 1 分钟,c++ 版本最快也要约 20 秒(纯 cpu 单线程,多线程的边界情况处理器来很麻烦所以没折腾成),而 Box blur 同样的图片虽然可以在几秒内完成,但对于某类图片(比如带明显横竖条纹的)的模糊效果非常差,即使两次 Box blur 出来的效果也还是差强人意。自行实现模糊的另一个要命的问题是内存。例如 StackOverflow 的这个 FastBlur 答案(很多讲模糊文章都引用了这个答案),虽然速度上还不错,但是内存消耗的实在是有点粗放,只适合做小图片处理。

据说 API 17 以上 Android 提供了 RenderScript 来可以利用 GPU 做模糊计算。去年底的时候我参考这篇折腾过,不过没成功。一是 API 17 这个门槛实在是高(貌似通过 android-support-v8 也可以,但也非常折腾),二是 RenderScript 调试起来实在困难。总之 RenderScript 这条路我没走通。前阵子又有一篇文章带了示例代码,有兴趣的同学可以继续尝试。需要注意的是像这种高大上的解决方案,兼容性有待验证(Android 设备的又一个命门)。但是这篇文章末尾提到的先 scale down 再模糊的想法很聪明——当时我仅尝试了直接 scale down 然后拉伸显示,效果惨不忍睹,于是就没有朝这个方向做更多努力,可能 scale down 之后再模糊一遍效果会好很多——实际上,在资源受限的设备上,很多时候工程师就是在功能、效果和速度之间在玩平衡游戏。
发表评论