Android模糊示例-RenderScript-附效果图与代码

本文链接    http://blog.csdn.net/xiaodongrush/article/details/31031411

参考链接    Android高级模糊技术    http://stackoverflow.com/questions/14879439/renderscript-via-the-support-library

1. 程序截图

    拖动红色区域,可以显示出清晰的汽车部分。拖动下面的滑块,可以更改模糊程度。

      
  

2. 程序实现方法

实现思路,用FrameLayout搞了三层,最底下一层是清晰的图片,中间一层是模糊的图片,最上面的一层,是红色区域,这一层是清晰的图片。

	public static class PlaceholderFragment extends Fragment { // 新版android adt-bundle默认在activity中带一个fragment,据说android stdio早就这样了

		private ImageView mOriginIv;

		private ImageView mBlurIv;

		private ImageView mClearIv;

		private SeekBar mRadiusSb;

		public PlaceholderFragment() {
		}

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_main, container,
					false);
			return rootView;
		}

		@Override
		public void onActivityCreated(Bundle savedInstanceState) {
			super.onActivityCreated(savedInstanceState);
			mOriginIv = (ImageView) getActivity().findViewById(
					R.id.origin_image);
			mBlurIv = (ImageView) getActivity().findViewById(R.id.blur_image);
			mClearIv = (ImageView) getActivity().findViewById(R.id.clear_image);
			mRadiusSb = (SeekBar) getActivity().findViewById(
					R.id.radius_seekbar);
			drawBlurImage(); // 初始化模糊层。
			setSeekBarChangeListen(); // 设置SeekBar回调,滑块位置变化的时候,更新模糊层。
                        // 延迟是为了保证view.getX,view.getWidth 这类方法能够去到数值,这里只是为了初始化,所以延迟执行比较好。
                        // 如果要是每次可视化的时候,都要读weidht和x,那么可以再在Activity#onWindowFocusChange中调用。
			Runnable runnable = new Runnable() {

				@Override
				public void run() {
					OnMoveListener listener = new OnMoveListener() {

						@Override
						public void onMoved() {
							mOriginIv.buildDrawingCache();
							clear(mOriginIv.getDrawingCache(), mClearIv, 10); // 这是拿到View绘制图像的好办法
						}
					};
					MoveUtils.enableMove(mClearIv, listener);
				}
			};
			mClearIv.postDelayed(runnable, 500);
		}

		private void drawBlurImage() {
			mOriginIv.getViewTreeObserver().addOnPreDrawListener(
					new OnPreDrawListener() {

						@Override
						public boolean onPreDraw() {
							mOriginIv.getViewTreeObserver()
									.removeOnPreDrawListener(this);
							mOriginIv.buildDrawingCache();
							float radius = mRadiusSb.getProgress();
							if (radius < 0.1) { // RenderScript要求radius必须在0和25之间,不能等于
								radius = 0.1f;
							}
							if (radius > 24.9) {
								radius = 24.9f;
							}
							blur(mOriginIv.getDrawingCache(), mBlurIv, radius);
							clear(mOriginIv.getDrawingCache(), mClearIv, 10); // 这里为了显示边框,偷懒了直接用了10px,实际上是5dip,在我的手机galaxy nexus上,1dip=2px,实际上应该换算一下的。
							return true; // 这个是参考文章中要求的,没试过false。
						}
					});
		}

		private void setSeekBarChangeListen() {
			mRadiusSb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

				@Override
				public void onStopTrackingTouch(SeekBar arg0) {
				}

				@Override
				public void onStartTrackingTouch(SeekBar arg0) {
				}

				@Override
				public void onProgressChanged(SeekBar arg0, int arg1,
						boolean arg2) {
					drawBlurImage();
				}
			});
		}

		// 首先根据view的大小,从bkg生成一个剪裁后的图像;然后根据radius,将剪裁后的图像模糊处理;最后将模糊处理的图像设置到view上。
		@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
		private void blur(Bitmap bkg, View view, float radius) {
                       // 剪裁图片的过程
			Bitmap overlay = Bitmap.createBitmap(
					(int) (view.getMeasuredWidth()),
					(int) (view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(overlay);
			canvas.translate(-view.getX(), -view.getY()); // 这里是设置坐标系原点
			canvas.drawBitmap(bkg, 0, 0, null); // // 这里直接在新的坐标系的原点上绘制图像,如果不设置坐标系的话,相当于在(view.getX(),view.getY)上绘制图像,android向右是x轴正方形,向下时y轴正方向。
                        // 模糊图片的过程
			RenderScript rs = RenderScript.create(getActivity()); // RenderScript要求apilevel 17,这个比较恶心,v8支持包也不是特别好用,真的要搞模糊的话,还是opencv jni来搞吧。
			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();
		}

                // 首先根据view的大小,从bkg生成一个剪裁后的图像;然后将剪裁后的图像设置到view上。
		private void clear(Bitmap bkg, ImageView view, int paddingPx) {
			Bitmap overlay = Bitmap.createBitmap(
					(int) (view.getMeasuredWidth() - paddingPx * 2),
					(int) (view.getMeasuredHeight() - paddingPx * 2),
					Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(overlay);
			canvas.translate(-view.getX() - paddingPx, -view.getY() - paddingPx);
			canvas.drawBitmap(bkg, 0, 0, null);
			view.setImageDrawable(new BitmapDrawable(getResources(), overlay));
		}

	}

3. 代码下载

万恶的CSDN上传了代码,好几个小时了还没审核完。。。http://download.csdn.net/detail/u011267546/7502603     注意代码的minsdk我设置的比较高,是API Level17,没办法,RenderScript的支持库没搞定。

4. 几个问题

RenderScript     虽然有support-v8支持库,但是我搞了会,也没编译成功。也看到有帖子说在2.3.5上RenderScript有问题的。所以感觉不是特别靠谱,还是jni+opencv自己搞起来比较好,网上opencv相关的模糊算法很多。另外如果图像很大,模糊处理比较耗时,最好是异步进行。

getWidth,getHeight,getLeft的调用时机      onStart、onReusme这些都不行,只能在onWindowFoucsChange。本文的示例是初始化的时候调用,所以可以延迟一会执行,如果要是每次从后台切换到前台,就要调用的话,那么要在onWindowFoucsChange中调用。

使用canvas剪裁bitmap     注意坐标系,android向右是x轴正方形,向下时y轴正方向。

private void clear(Bitmap bkg, ImageView view, int paddingPx) {
			Bitmap overlay = Bitmap.createBitmap(
					(int) (view.getMeasuredWidth() - paddingPx * 2),
					(int) (view.getMeasuredHeight() - paddingPx * 2),
					Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(overlay);
			canvas.translate(-view.getX() - paddingPx, -view.getY() - paddingPx);
			canvas.drawBitmap(bkg, 0, 0, null);
			view.setImageDrawable(new BitmapDrawable(getResources(), overlay));
		}

获取图片绘制缓存

mOriginIv.buildDrawingCache();
clear(mOriginIv.getDrawingCache(), mClearIv, 10);

让View可以拖动

写了一个简单的方法,通过View的Tag+onTouchEvent,实现View可以拖动。

package com.example.blurtest;

import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class MoveUtils {
	private static final int STATE_IDLE = 0;
	private static final int STATE_MOVING = 1;
	private static final int MIN_GAP = 5;

	private static class Info {
		public int state = STATE_IDLE;
		public float lastX = -1;
		public float lastY = -1;
		public OnMoveListener listener;
	}

	private static Info getInfo(View view) {
		if (view.getTag() == null) {
			view.setTag(new Info());
		}
		return (Info) (view.getTag());
	}

	private static void tryToMove(View view, MotionEvent ev) {
		Info info = getInfo(view);
		if (info.state != STATE_MOVING) {
			return;
		}
		float x = ev.getX() - info.lastX;
		float y = ev.getY() - info.lastY;
		if (Math.abs(x) < MIN_GAP && Math.abs(y) < MIN_GAP) {
			return;
		}
		view.setX(view.getX() + x);
		view.setY(view.getY() + y);
		view.invalidate();
		info.listener.onMoved();
	}

	public static void enableMove(View target, OnMoveListener listener) {
		Info info = new Info();
		info.listener = listener;
		target.setTag(info);
		target.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View view, MotionEvent ev) {
				Info info = getInfo(view);
				int action = ev.getAction() & MotionEvent.ACTION_MASK;
				switch (action) {
				case MotionEvent.ACTION_DOWN:
					info.state = STATE_MOVING;
					info.lastX = ev.getX();
					info.lastY = ev.getY();
					view.setTag(info);
					break;
				case MotionEvent.ACTION_MOVE:
					tryToMove(view, ev);
					break;
				case MotionEvent.ACTION_UP:
					info.state = STATE_IDLE;
					info.lastX = ev.getX();
					info.lastY = ev.getY();
					view.setTag(info);
				default:
					break;
				}
				return true;
			}
		});
	}

	public static interface OnMoveListener {
		public void onMoved();
	}
}

Android模糊示例-RenderScript-附效果图与代码

时间: 2024-10-13 12:41:48

Android模糊示例-RenderScript-附效果图与代码的相关文章

JQ写简单的伸缩菜单(内附效果图和源代码)

效果如图: JQ代码就那么几句, <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-cn"> <

JQ写下拉列表项目移动,还存在2个小BUG(内附效果图和源代码)

效果图如下: 实现功能:点击第一个按钮,让选中的对象从左边移动到右边: 点击第二个按钮,让左边的所有对象移动到右边: 点击第三个按钮,让选中的对象从右边边移动到左边:   点击第四个按钮,让右边的所有对象移动到左边. 存在BUG:点击第一个或者第三个按钮,不选择对象也能让末位的对象移动到另外一个框中: 选中2个以上的对象,点击第一或者第三个按钮,只能移动一个对象到另一边. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN&quo

Android拍照+方形剪裁——附代码与效果图

本文链接    http://blog.csdn.net/xiaodongrush/article/details/29173567 参考链接    http://stackoverflow.com/questions/12758425/how-to-set-the-output-image-use-com-android-camera-action-crop 1. 缘起 要开发一个头像上传的模块,头像上传过程分两步.第一步,相机拍照或者从图库选取照片,产生一个照片,第二步,提供头像剪裁,一般是

爬虫技术(四)-- 简单爬虫抓取示例(附c#代码)

这是我的第一个爬虫代码...算是一份测试版的代码.大牛大神别喷... 通过给定一个初始的地址startPiont然后对网页进行捕捉,然后通过正则表达式对网址进行匹配. List<string> todo :进行抓取的网址的集合 List<string> visited :已经访问过的网址的集合 下面实现的是,给定一个初始地址,然后进行爬虫,输出正在访问的网址和已经访问的网页的个数. 需要注意的是,下面代码实现的链接匹配页面的内容如图一.图二所示: 图一: 图二: 简单代码示范如下:

Android客户端与服务端(jsp)之间json的传输与解析【附效果图附源码】

最近有个项目需要用到json的传输,之前不是太了解,在网上找了些相关资料,写了一个小小的demo,可以实现基本功能:android客户端发送json到服务端,服务端使用jsp接收,解析后以json的形式返回给客户端,客户端接收打印,先看看运行的效果截图,源码会在文章的末尾给出. 1.服务端:接收到json后解析打印,然后发送json到客户端 2.客户端,收到服务端返回的json后打印 简单的介绍下源码: 服务端使用json.jsp来接收解析客户端传过来的json,json的解析需要使用lib目录

微信Android SDK示例代码及运行方法

最近在研究微信SDK,无奈网上好使的教程太少,对于程序员来说最好的东西,一个是微信的开发文档,一个是微信SDK的范例代码.无奈文档小白很难看懂,范例代码又没有详细的解释,导致我折腾了好多天,现在有点眉目了,先记下来. 1.申请应用AppKey 微信的SDK要求应用的包名.签名的MD5.AppID严格对应,所以没有申请的应用是肯定无法使用的.申请了的应用如果这三个对不上,是无法使用的. ·包名,是应用建立时候的名称,你可以在AndroidManifest.xml文件的package项中找到 ·签名

【COCOS2D-HTML5 开发之三】示例项目附源码及运行的GIF效果图

本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/cocos2d-html5/1528.html ? 点击订阅 ? 本博客最新动态!及时将最新博文通知您! Cocos2dx html5开发,对于用过2d Or -x的童鞋来说很容易,Himi这里也没有必要去再跟同学们详细的教学一遍. 所以Himi简单做了一个项目,供给大家参考,源码下载地址及GIF截图在文章最后!

Django内置过滤器详解附代码附效果图--附全部内置过滤器帮助文档

前言 基本环境 Django版本:1.11.8 Python版本:3.6 OS: win10 x64 本文摘要 提供了常用的Django内置过滤器的详细介绍,包括过滤器的功能.语法.代码和效果示例. 本文完整项目文件代码下载地址:完整示例 Django完整内置过滤器帮助文档:Django内置过滤器完整版 参考文献:Django 中文文档 1.8 内置过滤器 注意:所有带参数的过滤器,在使用时,冒号:和参数中间不能有空格. add加 功能: 把add后的参数num加给value: 数字相加会进行算

Android高效计算——RenderScript(二)

3 RenderScript运行时层与反射层 3.1 RenderScript运行时层 RenderScript运行时层是指.rs代码运行时所在的层级.当对安卓项目进行编译的时候,.rs或者.rsh中编写的代码都会被llvm编译器编译成字节码.当该安卓应用在设备上运行的时候,这些字节码将会被设备上另外一个llvm编译(just-in-time)成机器码.这些机器码是针对该设备进行了优化的,且缓存在设备上,等到下次被应用的时候就不需要重新编译了,以加快速度.虽然RenderScript运行时层很像