MOO 音乐中的Flutter 模糊方案分析

2021-02-25 12:10:05 浏览数 (1)

前言

对图片进行模糊化处理,是非常常见的开发场景。在MOO音乐App的模糊优化过程中,我们总结了一些Flutter中模糊使用的一些经验。在确定模糊方案的过程中我们遇到两个选择点,模糊逻辑实现和模糊算法的选择,针对这两个选择点我们设计了四个方案用作对比。

  • 方案一: Flutter BackdropFilter & GaussianBlur
  • 方案二: Dart StackBlur & StackBlur
  • 方案三: Golang GaussianBlur & GaussianBlur
  • 方案四: Golang HashBlur & HashBlur

方案之间对比我们主要从四个方面考虑,空间占用、模糊耗时、模糊效果、同一图片是否重复计算。

方案一:BackdropFilter

Flutter本身为开发者提供了绘制过滤控件BackdropFliter,我们可以使用它提供的ImageFilter#blur来实现GaussianBlur的效果。我们简单的将BackdropFliter套在需要模糊的控件外部即可。具体使用方法可以参考官方教程。

BackdropFilter的实现原理是在RenderObject#paint方法中对Layer当前的图像数据做处理。优势在于模糊是实时的即使背景是gif也能做到实时模糊。缺点是在面对滚动、动画等需要频繁repaint的场景实时计算的耗时会导致很大程度的卡顿。

针对滚动的场景我们做了一组对照实验

未添加BackDropFilter时,SkCanvas#flush平均耗时1.448ms,添加BackDropFilter时SkCanvas#flush平均耗时3.314ms。

SkCanvas#flush是Flutter Engine将layer数据渲染到屏幕上所调用的方法从图上我们对比出添加BackDropFilter的SKCavans#flush方法的耗时相比未添加BackDropFilter平均增多 2ms,且耗时波动较大。一帧的绘制时间应尽可能的在 16ms 内,从数据上看使用BackDropFilter会增加 GPU 的绘制时间。

方案二:StackBlur

GaussianBlur的耗时相对来说会比较高,这里选用了效果和GaussianBlur近似,计算速度更快的StackBlur模糊算法。

在ImageWidget加载图片的过程中获取到图片的信息,通过模糊算法计算得模糊后的图片信息,再将它设置给ImageWidget。

由于StackBlur需要接收decode后的图片数据,而Flutter的Image Widget又只能接收encode后的图片数据。并且decode(标记1)和encode(标记2)是耗时操作,因此这个方案在客户端上的耗时会更高一些,详细的数据可以查看表《方案二、方案三 耗时对比》。对于耗时操作我们在Native的常用方案是切换到非主线程执行,等执行完成后再切回主线程操作。在Dart中我们可以使用Isolate来实现类似的效果。不过这带来了新的问题,Isolate是严格的资源隔离的,图片资源需要复制多份在新Isolate和主线程中流转,这会直接导致Dart内存的增加。

方案三:服务端 GaussianBlur

模糊图片的计算逻辑由服务端处理,客户端负责将模糊的后的图片下载、展示。这种方式的优势是同样的图片模糊结果可以由服务端缓存,避免了重复计算;客户端不需要处理相对比较耗时的模糊计算逻辑。

方案二 和 方案三 主要区别在模糊计算是由客户端还是服务端处理。因此我们选用了四张大小不同的图片做了对比实验。因为处理后图片的大小基本一致,所以着重对比了两者的渲染耗时数据。

方案四:服务端 BlurHash

使用BlurHash在服务端计算得模糊后的HashCode,交由客户端渲染出对应的图片BlurHash的计算逻辑和其他模糊方式有比较大的区别,它的核心是将图片切割成若干矩形,然后分别计算它们的颜色向量,最后将这些数据储存在长度 20-30 的字符串中。相比其他的模糊方式它的优势是储存的大小要小很多,缺点是模糊后的图片和原图差距较大,因为它丢失了更多的数据。

影响BlurHash耗时的主要因素是decode高宽的数值,因此我们统计了 50* 50、200 * 200、500* 500 三种图片大小的耗时数据参与对比。又因为App通常需要的图片区域约为 200 * 200 因此选用这个情况下的耗时数据与方案二、方案三对比。

最后再附上 储存大小模糊效果 的对比结果。

总结

方案一可以支持动态的模糊,但在repaint较多的场景会导致一定程度的卡顿;方案二解析速度慢,图片大小方面也不具有优势;方案三减少了客户端的压力,并且模糊后的图片可以由服务端缓存,避免了重复计算。但依赖网络,网络状态差或无网络状态,表现不理想;方案四方案三相比储存大小更小了,但模糊效果不太理想。

每个方案各有利弊,我们应该针对场景来选择对应的方案。在条件允许的情况下应该优先选择方案一,如果是预览并且图片尺寸比较小的场景,可以考虑采用方案四。其余情况应该优先考虑方案三

参考文章

1. 官方教程:https://www.youtube.com/watch?v=dYRs7Q1vfYI

QQ音乐招聘Android/ios客户端开发,点击左下方“查看原文”投递简历~

也可将简历发送至邮箱:tmezp@tencent.com

0 人点赞