这两天看到公司工程里有用到高斯模糊,是通过java实现的,很慢,所以找了一些资料,看到RenderScript,性能很好,而且RenderScript是可以兼容低版本的,实现方式也是jni。兼容低版本的教程网上有很多,就是在sdk目录里把RenderScript v8包添加到自己的工程里,并且把jni的文件添加到自己的项目里。这里把只把代码和方法发出来。
/** * 初始化控件 */ private void initView(){ iv_gaussian = (ImageView)findViewById(R.id.iv_gaussian); tv_time = (TextView)findViewById(R.id.tv_time); long timeStart = SystemClock.currentThreadTimeMillis(); Bitmap bitmap = blurBitmap(getBitmapFromDrawable(),this); time = SystemClock.currentThreadTimeMillis()-timeStart; iv_gaussian.setImageBitmap(bitmap); tv_time.setText("耗时:"+time); } /** * 获取资源文件的bitmap * @return */ private Bitmap getBitmapFromDrawable(){ Resources res = getResources(); return BitmapFactory.decodeResource(res, R.mipmap.bg_1,getScaleOptions(res,R.mipmap.bg_1,200,200)); } /** * 执行高斯模糊 * * @param bitmap * @param context * @return */ public Bitmap blurBitmap(Bitmap bitmap, Context context) { // 用需要创建高斯模糊bitmap创建一个空的bitmap Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); // 初始化Renderscript,这个类提供了RenderScript context, // 在创建其他RS类之前必须要先创建这个类,他控制RenderScript的初始化,资源管理,释放 RenderScript rs = RenderScript.create(context); // 创建高斯模糊对象 ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // 创建Allocations,此类是将数据传递给RenderScript内核的主要方法, // 并制定一个后备类型存储给定类型 Allocation allIn = Allocation.createFromBitmap(rs, bitmap); Allocation allOut = Allocation.createFromBitmap(rs, outBitmap); // 设定模糊度 blurScript.setRadius(25.f); // Perform the Renderscript blurScript.setInput(allIn); blurScript.forEach(allOut); // Copy the final bitmap created by the out Allocation to the outBitmap allOut.copyTo(outBitmap); // recycle the original bitmap bitmap.recycle(); // After finishing everything, we destroy the Renderscript. rs.destroy(); return outBitmap; } /** * 获取压缩比例的options * @param width 图片的最大宽度 * @param height 图片的最大高度 * @return */ private BitmapFactory.Options getScaleOptions(Resources res,int resId,int width,int height){ BitmapFactory.Options newOpts = new BitmapFactory.Options(); // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 newOpts.inJustDecodeBounds = true; // newOpts.inJustDecodeBounds = false; //空的bitmap,不占内存,只是为了拿到宽和高 不需要回收 Bitmap bitmap = BitmapFactory.decodeResource(res,resId,newOpts); int w = newOpts.outWidth; int h = newOpts.outHeight; // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 int be = 1;// be=1表示不缩放 if (w > h && w > width) {// 如果宽度大的话根据宽度固定大小缩放 be = (int) (newOpts.outWidth / width); } else if (w < h && h > height) {// 如果高度高的话根据宽度固定大小缩放 be = (int) (newOpts.outHeight / height); } if (be <= 0) be = 1; newOpts.inSampleSize = be;// 设置缩放比例 LogUtils.showDebugLog("GaussianActivity","缩放比例:"+be); //因为外部的进行解码操作,所以这时候需要重新设为false newOpts.inJustDecodeBounds = false; return newOpts; }
执行高斯的代码是网上拷过来的,模糊半径最大只能设到25,可能对图片直接处理的时候会导致模糊的效果不太好,太清晰,但是可以通过降低图片的质量来实现更模糊的效果,不知道这个思路对不对,或者说性能上是不是会有什么不好影响,欢迎大家指正。
2016.4.14更新
昨天听同事说,图片的缩放会耗时,又看了一下代码,发现代码里有错误,现在订正过了,然后现在把时间的起始放到了缩放之前,耗时是70毫秒左右,图片大小是720*1080,缩放倍数是6
2016.6.24更新
jar包和.so版本的选择一定要选最新的,我现在用的是24.0.0,增加了x86-64的适配,体积也小了很多,老版本的在有些64位的机器上会闪退