Android毛玻璃效果 获取系统截屏 高斯模糊

本文详细介绍了如何获取屏幕截图,并通过剪裁和模糊处理技术来改善视觉效果。重点讨论了不同方法的实现步骤及性能优化,旨在提供高效、直观的屏幕截图展示方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    近期实现任意屏幕上滑弹出一个快捷栏,http://blog.youkuaiyun.com/kong92917/article/details/48023579。由于做完发现布局效果太差。刚巧看到ios的毛玻璃于是想模仿下。


注意点如下:上滑和弹出操作由于之前的动画和其他数据加载操作已经较为耗时,应尽量减少时间损耗。该方法是系统级别性质,应用级的实现更方便。


1、实现思路大概方向:

    a、获取屏幕截图

    b、对图片处理剪裁

    c、对处理后的图片进行模糊运算

2、具体实现:

a、获取屏幕截图:

    android L可以使用新的接口MediaProjection API,可参照http://binwaheed.blogspot.com/2015/03/how-to-correctly-take-screenshot-using.html。之前的版本请参照http://blog.youkuaiyun.com/buptgshengod/article/details/39155979。

但此处使用以上两种方法耗时都很明显,而且此处不需要保存图片为文件,第二种更是通过启动service来调用JNI实现截图,于是想到可以直接通过view来获取避免两次io流的操作。实现如下:

对于应用级的

	private Bitmap getWindowBitmap(View v) {
		View view = v.getRootView();// getDecorView();
		view.setDrawingCacheEnabled(true);
		view.buildDrawingCache(true);
		Bitmap bmpcache = view.getDrawingCache();		
		return bmpcache;
	}


   遇到getDrawCache为null时参考这博文http://www.cnblogs.com/devinzhang/archive/2012/06/05/2536848.html

    对于系统级需要获取其他每个界面的view截图,采用如上方法时发现获取不到DecorView(我是在phonewindowmanager下无法获取,待补充想过如下实现:

根据TopRunningProcess包名和Activity获取当前top顶层的实例,再activity.getWindow().getDecorView(); 该方法获取实例时(Class.forName(name.getClassName()).newInstance());获取到的是重新打开的activity实例,无法用于截取当前的view截图。

在phonewindow中使用DecorView,

<span style="font-family:FangSong_GB2312;font-size:14px;">    // This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;</span>
贴个别处盗的图,view.getDrawingCache()在PhoneWindow中也有通过DecorView类似实现


好吧,没想到其他办法了就先用这个。

测试发现。该方法获取当前屏幕的bitmap时,实时性和效率会有点问题,正在研究解决方法中,待补充


b、对图片处理剪裁

	/**
	 * 从屏幕截图中剪切出view控件的bitmap
	 * @param bkg 获取到的屏幕截图
	 * @param view 需要截取的图的大小,这里是截取view的大小,也可以直接定义截取范围
	 * @return
	 */
	private Bitmap cutBitmap(Bitmap bkg, View view) {
		float scaleFactor = 4;// 图片缩放比例;
		Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth() / scaleFactor),
				(int) (view.getMeasuredHeight() / scaleFactor), Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(overlay);
		canvas.translate(-view.getLeft() / scaleFactor, -view.getTop() / scaleFactor);//重新定义位置
		canvas.scale(1 / scaleFactor, 1 / scaleFactor);//缩放
		Paint paint = new Paint();
		paint.setFlags(Paint.FILTER_BITMAP_FLAG);
		canvas.drawBitmap(bkg, 0, 0, paint);
		return overlay;
	}

        也可使用这种方法

	private static Bitmap blur(Bitmap bkg) {
		float scaleFactor = 16;// 图片缩放比例;
		Matrix matrix = new Matrix();
		matrix.postScale(1/scaleFactor, 1/scaleFactor);
		Bitmap bitmapBlur = Bitmap.createBitmap(bkg, x, y, width, height, matrix, true);
		return bitmapBlur;
	}

    留意下为何要压缩图片。

c、对处理后的图片进行模糊运算

    使图片模糊大多使用的高斯算法,高斯模糊就是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值。主要点这两篇博客已经写得很不错了可直接参考:http://blog.jobbole.com/63894/  。http://blog.youkuaiyun.com/huli870715/article/details/39378349


    高版本可以利用现有Android结构,通过RenderScript调用底层接口实现高斯模糊计算,但这种方法模糊半径过大,大于25(数值来源知乎)时会产生性能问题。

//来源:知乎

// Remix Blur
private void blur(Bitmap bkg, View view) {
    …
    RenderScript rs = RenderScript.create(getActivity());
    Allocation overlayAlloc = Allocation.createFromBitmap(rs, overlay);
    ScriptIntrinsicBlur blur = 
        ScriptIntrinsicBlur.create(rs, overlayAlloc.getElement());
    blur.setInput(overlayAlloc);
    blur.setRadius(radius);
    blur.forEach(overlayAlloc);
    overlayAlloc.copyTo(overlay);
    view.setBackground(new BitmapDrawable(getResources(), overlay));
    rs.destroy();
}


    由于单纯的进行高斯模糊仍然会执行很长时间,我使用上个链接提供的方法耗时大概是200ms~500ms不等,依机型和图片大小质量有关。由于高斯模糊是与周边像素加权平均后的值,高斯运算时对于高质量图片会做出大量循环加权平均,所以可以现将图片压缩减小运算时的量,得到的效果也几乎没有差别。测试发现压缩10倍后,高斯运算的时间可以控制在100ms以内。

但是!

    在Android中渲染一帧的时间应该不超过16ms(60fps)。虽然没有太大的卡顿,但还是问题还是会有,参看了微博最新版本点击中间+号的模糊背景,发现模糊化过大只能显示下方的橙色,我觉得更可能它是直接用的一张模糊图片。



以上仅作为学习记录

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值