当前位置: 首页 > 科技观察

一个快速的磨砂玻璃虚化效果实现

时间:2023-03-16 11:38:40 科技观察

我们在iOS设备上随处可见磨砂玻璃效果,最近越来越多的场合应用了这种漂亮的虚化效果,包括我的一个开源项目BlureImageView,也是受到了启发这样。因此,适当的模糊效果可以很好的提升用户体验,也可以让你的应用看起来更加优雅。但是,目前我们很少在安卓上看到磨砂玻璃效果。我认为重要的原因是性能问题。模糊图片所需的时间因设备而异。如果用户需要刻意等待模糊,那么弊大于利。另外,Google官方提供的renderScript一般只做一些小的模糊,很难做到像毛玻璃这样的深度模糊效果。所以这篇文章的重点是在Android设备上快速实现毛玻璃效果。StackBlur首先,为了实现毛玻璃效果,本文采用StackBlur模糊算法,该算法应用广泛,可以得到非常好的毛玻璃效果。这里,我们使用的是它的Java实现代码FastBlur.java。publicstaticBitmapdoBlur(BitmapsentBitmap,intradius,booleancanReuseInBitmap)可以看到,使用方法很简单,输入要模糊的位图,模糊程序(一般8个),是否复用标志位。那么,如果我们要对上面的图片进行模糊处理,我们可以将其转换成位图,然后传入模糊处理,这似乎很容易解决,但事实并非如此。OOM如果直接传入大图,容易OOM内存溢出jayandroidI/art:ClamptargetGCheapfrom109MBto96MB03-1121:02:02.03016727-16727/com.wingjay.jayandroidI/art:ClamptargetGCheapfrom109MBto96MB03-1121:02:02.03116727/com.16727/com.16727wingjay.jayandroidI/art:ForcingcollectionofSoftReferencesfor30MBallocation03-1121:02:02.03516727-16727/com.wingjay.jayandroidI/art:ClamptargetGCheapfrom109MBto96MB03-1121:02:02.03616727-16727/com.wingjay.jayandroidE/art:ThrowingOutOfMemoryError"Failedtoallocatea32175012byteallocationwith2648672freebytesand2MBuntilOOM"03-1121:02:02.03616727-16727/com.wingjay.jayandroidD/AndroidRuntime:ShuttingdownVM这是直接对原图进行模糊处理得到的日志信息。可以看到,当虚拟化开始时,虚拟机开始不断的回收内存,包括回收所有的软引用内存。但是,它仍然会导致内存溢出。这意味着我只能模糊小图像,以防止内存溢出。但是我不想改变其他图片,所以我们应该缩放这张图片。ReScalepublicstaticBitmapcreateScaledBitmap(Bitmapsrc,intdstWidth,intdstHeight,booleanfilter){}我们可以使用这个函数来缩放位图。其中,前三个参数显而易见,其中我们可以选择宽高为原图尺寸的1/10;第四个滤镜是指缩放效果,如果滤镜为真,会得到一个边缘平滑的位图;否则,将得到边缘参差不齐、像素相关的位图。这里我们要对缩放后的图片进行模糊处理,所以无所谓边缘效果,filter=false。所以,我们要使用intscaleRatio=10;intblurRadius=8;BitmapscaledBitmap=Bitmap.createScaledBitmap(originBitmap,originBitmap.getWidth()/scaleRatio,originBitmap.getHeight()/scaleRatio,false);BitmapblurBitmap=FastBlur.doBlur(scaledBitmap,blurRadius,真的);imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);imageView.setImageBitmap(blurBitmap);可以得到如下效果:从图中可以看出,首先可以判断思路是正确的;然后,可以看到磨砂玻璃效果并不是特别明显。为了得到像iOS那样的模糊效果,我们有两种方法:增加scaleRatio的缩放比例,使用同样较小的位图去模糊,得到更好的模糊效果,有利于减少内存占用;增加blurRadius,可以获得更高的模糊度,但是会导致CPU更加密集。在这里,我通过增加缩放比例进行实验。scaleRatio=20scaleRatio=35scaleRatio=50scaleRatio=100通过上面的对比图,我们可以找出最适合自己的模糊效果。性能分析那么,实现这样的效果,是否存在破坏用户体验的风险呢?接下来我们从耗时和内存占用的角度来分析。耗时为了分析对一张图片进行模糊处理所消耗的时间,本文通过同时对100张图像进行模糊处理得到平均耗时。从而对模糊的耗时效果以及不同缩放比例对耗时的影响有一定的了解。longstart=System.currentTimeMillis();BitmapscaledBitmap,blurBitmap;intscaleRatio=10;intloopCount=100for(inti=0;iscaleRatio=10:耗时887ms,平均耗时8.87ms;scaleRatio=20:耗时224ms,平均耗时2.24ms;scaleRatio=35:耗时99ms,平均耗时0.99ms;scaleRatio=50:耗时55ms,平均耗时0.55ms;scaleRatio=100:耗时29ms,平均耗时-耗时0.29ms;为了方便读者理解效果,我通过多组数据拟合如下曲线:从仿真图中可以看出,时间随着缩放比例的增加而减少。ratio达到30以上,消耗的时间不到1ms,所以我觉得应该是完全没有延迟损害用户体验,既然内存消耗没问题,那么主要问题:内存占用来了,所以我们需要检查生成模糊图片所占用的内存e.为了测试改变模糊一张图片占用的内存,我们改变模糊的次数,也就是修改上面的loopCount,观察内存的变化。其中scaleRatio=10获得比较大的内存消耗。loopCount=1loopCount=10loopCount=20loopCount=50loopCount=100loopCount=300从上面的内存消耗图可以看出,模糊处理确实占用了一定的内存。如果同时出现大量的模糊,会是UI线程突然加载大量位图造成的内存抖动。结语希望大家如果有其他的测试方法或者意见,多多留言,以便继续提高性能。附上本文使用的方法