【Android实战】Bitmap图片的截屏、模糊处理、传递、使用
项目中遇到了这样一个需求:
当某个条件满足时就截取当前屏幕。并跳转到另外一个页面,同一时候将这个截屏图片作为下一个页面的背景图片,同一时候背景图片须要模糊处理
接下来就一步一步解决这个问题:
1、截取无状态栏的当前屏幕图片。请參考takeScreenShot方法
2、使图片高斯模糊的方法请參考blurBitmap方法
注意:RenderScript是Android在API 11之后增加的,用于高效的图片处理,包含模糊、混合、矩阵卷积计算等
public class ScreenShotUtil { // 获取指定Activity的截屏,保存到png文件 String filenameTemp = "/mnt/sdcard/temp"; /** * takeScreenShot: * TODO 截屏 去掉标题栏 * @param activity */ public static Bitmap takeScreenShot(Activity activity) { // View是你须要截图的View View view = activity.getWindow().getDecorView(); view.setDrawingCacheEnabled(true); view.buildDrawingCache(); Bitmap b1 = view.getDrawingCache(); // 获取状态栏高度 Rect frame = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; LogHelper.i("TAG", "" + statusBarHeight); // 获取屏幕长和高 int width = activity.getWindowManager().getDefaultDisplay().getWidth(); int height = activity.getWindowManager().getDefaultDisplay().getHeight(); // 去掉标题栏 // Bitmap b = Bitmap.createBitmap(b1, 0, 25, 320, 455); Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height - statusBarHeight); view.destroyDrawingCache(); return b; } /** * TODO 用于高效的图片处理,包含模糊、混合、矩阵卷积计算等 * @param bitmap * @param context */ @SuppressLint("NewApi") public static Bitmap blurBitmap(Bitmap bitmap, Context context) { // Let's create an empty bitmap with the same size of the bitmap we want // to blur Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); // Instantiate a new Renderscript RenderScript rs = RenderScript.create(context);//RenderScript是Android在API 11之后增加的 // Create an Intrinsic Blur Script using the Renderscript ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); // Create the Allocations (in/out) with the Renderscript and the in/out // bitmaps Allocation allIn = Allocation.createFromBitmap(rs, bitmap); Allocation allOut = Allocation.createFromBitmap(rs, outBitmap); // Set the radius of the blur 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; } }
3、传递bitmap
刚開始我是这么传递的
bundle.putParcelable("bitmap", ScreenShotUtil.takeScreenShot(theLayout.getActivity()));
继续以下操作:就是将bitmap封装到bundle中,然后封装到intent中启动下一个Activity
ActivityUtil.startActivity(theLayout.getActivity(), LiveEndActivity.class, bundle, false);
/** * 开启另外一个activity * * @param activity * @param cls 另外的activity类 * @param bundle 传递的bundle对象 * @param isFinish true表示要关闭activity false表示不要关闭activity */ public static void startActivity(Activity activity, Class<?> cls, Bundle bundle, boolean isFinish) { Intent intent = new Intent(activity, cls); if (bundle != null) { intent.putExtras(bundle); } activity.startActivity(intent); if (isFinish) { activity.finish(); } activity.overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); }然后在LiveEndActivity中这么解析
Bitmap bitmap = intent.getExtras().getParcelable("bitmap");结果:无法得到预期效果
关键是不报错。debug的时候能够看到我们的确截屏成功,可是Bitmap对象就是没有传递过去,并且不是启动下一个Activity
然后去网上找方法调研
结论:不能直接传递大于40k的图片
解决的方法:把bitmap存储为byte数组,然后再继续传递
Bitmap bitmap = ScreenShotUtil.takeScreenShot(theLayout.getActivity()); ByteArrayOutputStream baos=new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); byte [] bitmapByte =baos.toByteArray(); bundle.putByteArray("bitmap", bitmapByte); // bundle.putParcelable("bitmap", ScreenShotUtil.takeScreenShot(theLayout.getActivity())); ActivityUtil.startActivity(theLayout.getActivity(), LiveEndActivity.class, bundle, false);
然后在下一个Activity中这么解析
byte[] bis =intent.getExtras().getByteArray("bitmap"); Bitmap bitmap=BitmapFactory.decodeByteArray(bis, 0, bis.length);
4、假如我们须要将这张图片设置为我们当前Activity的背景图片。我们能够这么做
if (bitmap != null) { bitmap = ScreenShotUtil.blurBitmap(bitmap,getApplicationContext());//高斯模糊处理 getWindow().getDecorView().setBackgroundDrawable(new BitmapDrawable(bitmap)); }
问题基本攻克了。认为实用的能够參考一下!
更新补充:
2015.08.23
* blurBitmap方法在4.2及以上的版本号就能够轻松出效果了。可是在低版本号就会出异常:
* java.lang.NoClassDefFoundError: android.renderscript.ScriptIntrinsicBlur。
* 解决方法:详见http://blog.csdn.net/yangxin_540/article/details/47207727
* 可是我在使用该解决方法时easy出现其他so库 native方法异常的问题
所以找到了第二种方法
/** * blurImageAmeliorate:模糊效果 * http://blog.csdn.net/sjf0115/article/details/7266998 * @param bmp * @return */ public static Bitmap blurImageAmeliorate(Bitmap bmp) { long start = System.currentTimeMillis(); // 高斯矩阵 int[] gauss = new int[] { 1, 2, 1, 2, 4, 2, 1, 2, 1 }; int width = bmp.getWidth(); int height = bmp.getHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); int pixR = 0; int pixG = 0; int pixB = 0; int pixColor = 0; int newR = 0; int newG = 0; int newB = 0; int delta = 75; // 值越小图片会越亮,越大则越暗 int idx = 0; int[] pixels = new int[width * height]; bmp.getPixels(pixels, 0, width, 0, 0, width, height); for (int i = 1, length = height - 1; i < length; i++) { for (int k = 1, len = width - 1; k < len; k++) { idx = 0; for (int m = -1; m <= 1; m++) { for (int n = -1; n <= 1; n++) { pixColor = pixels[(i + m) * width + k + n]; pixR = Color.red(pixColor); pixG = Color.green(pixColor); pixB = Color.blue(pixColor); newR = newR + (int) (pixR * gauss[idx]); newG = newG + (int) (pixG * gauss[idx]); newB = newB + (int) (pixB * gauss[idx]); idx++; } } newR /= delta; newG /= delta; newB /= delta; newR = Math.min(255, Math.max(0, newR)); newG = Math.min(255, Math.max(0, newG)); newB = Math.min(255, Math.max(0, newB)); pixels[i * width + k] = Color.argb(255, newR, newG, newB); newR = 0; newG = 0; newB = 0; } } bitmap.setPixels(pixels, 0, width, 0, 0, width, height); long end = System.currentTimeMillis(); return bitmap; }
以下假设还有什么问题。我会继续更新!