截屏相关

前段时间在做一个截屏分享的功能,所截取的内容包括一个surfaceView+MediaPlayer的视频,虽然最终实现了该功能,但是确实也走了很多弯路,当时本想总结一下的,但后来一直拖着没弄。最近又涉及到包含listView(要截取listView全部内容,包括屏幕以外的部分)截屏,弄完了就在此记录一下方便以后查看,免得过段时间忘了,又得到处找。

surfaceView截屏思路:

1.、先截取整个静态屏幕(screenBitmap)

2、获取当前的视频帧图片(vedioBitmap)

3、将获取帧图片vedioBitmap绘制在screenBitmap的黑色区域

 

首先截取静态屏幕,代码如下

<span style="white-space:pre">	</span>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;
		System.out.println(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();
		savePic(b, "/sdcard/screen_test.png");
		return b;
	}


这个方法截取静态屏幕是没问题的,但视频部分截出来的趋势黑色一片,根本不能看,主要是surfaceView的实现原理,如下:

  SurfaceView通常有两个缓冲区(buffer), 一个front buffer,一个back buffer。而back buffer就是Canvas对应的bitmap。每当frong buffer显示时,back buffer就迅速的绘制,然后front buffer迅速将当前的back buffer显示给用户。由于速度十分快,所以便形成了动画效果。View是在UI的主线程中更新画面,而SurfaceView是在一个新线程中更新画面。这就需要你new一个新线程,在新线程里面进行绘画的工作。 SurfaceView通过SurfaceHolder对象将back buffer画好的内容更新到front buffer。 这也就是为什么我们在使用SurfaceView时需要将canvas进行锁定。 那么说了这么多,SurfaceView和普通View有什么区别? (静态与动态的区别)

主要在于普通View内容draw之后,是静态的,我们不调用invalidate它就放在那, 拿到了Bitmap之后,我们可以获取到里面的内容。但是SurfaceView不同,我们无法拿到back buffer里面的bitmap。所以我们以往常用的截屏方案就不能够达到截下SurfaceView的效果。

 

获取当前的视频帧图片,代码如下:

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private Bitmap createVideoThumbnail(String url, int width, int height) {
    Bitmap bitmap = null;
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    int kind = MediaStore.Video.Thumbnails.MINI_KIND;
    try {
      if (Build.VERSION.SDK_INT >= 14) {
        retriever.setDataSource(url, new HashMap<String, String>());
      } else {
        retriever.setDataSource(url);
      }
      bitmap = retriever.getFrameAtTime();
    } catch (IllegalArgumentException ex) {
      // Assume this is a corrupt video file
    } catch (RuntimeException ex) {
      // Assume this is a corrupt video file.
    } finally {
      try {
        retriever.release();
      } catch (RuntimeException ex) {
        // Ignore failures while cleaning up.
      }
    }
    if (kind == Images.Thumbnails.MICRO_KIND && bitmap != null) {
      bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,
          ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
    }
    return bitmap;
  }
最后根据自己的逻辑(计算好位置、图片的宽高等等),以获取的静态屏幕图片为画布,将获取的帧图片绘制在黑色区域,即可。

查看的关于截屏的文章如下:

http://blog.csdn.net/bboyfeiyu/article/details/12712141

http://blog.csdn.net/hk_256/article/details/7306590

http://blog.csdn.net/yilip/article/details/7745584

http://blog.csdn.net/linyukun6422/article/details/43191333

http://huobengluantiao8.iteye.com/blog/1578117

http://www.tuicool.com/articles/uqmUFfY

http://blog.csdn.net/woshinia/article/details/11520403



listView截屏思路(gridView类似):

              listView的截屏就比较简单了,主要是把每个item的view转换为bitmap,然后注意绘制在适当的位置就ok了。参考http://www.darcye.com/article/84263064


<span style="white-space:pre">	</span>public static Bitmap createBitmap(ListView listView, Context context) {
		int width, rootHeight = 0;
		int yPos = 0;
		int listItemNum;
		List<View> childViews = null;

		width = ViewUtil.getScreenWidth(context);// 宽度等于屏幕宽

		ListAdapter listAdapter = listView.getAdapter();
		listItemNum = listAdapter.getCount();
		childViews = new ArrayList<View>(listItemNum);
		View itemView;
		// 计算整体高度:
		for (int pos = 0; pos < listItemNum; ++pos) {
			itemView = listAdapter.getView(pos, null, listView);
			// measure过程
			itemView.measure(
					MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
					MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
			childViews.add(itemView);
			rootHeight += itemView.getMeasuredHeight();
		}

		Bitmap bitmap = Bitmap
				.createBitmap(width, rootHeight, Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);

		Bitmap itemBitmap;
		int childHeight;
		// 把每个ItemView生成图片,并画到背景画布上
		for (int pos = 0; pos < childViews.size(); ++pos) {
			itemView = childViews.get(pos);
			childHeight = itemView.getMeasuredHeight();
			itemBitmap = viewToBitmap(itemView, width, childHeight);
			if (itemBitmap != null) {
				canvas.drawBitmap(itemBitmap, 0, yPos, null);
			}
			yPos = childHeight + yPos;
		}
		canvas.save(Canvas.ALL_SAVE_FLAG);
		canvas.restore();
		return bitmap;
	}

<span style="white-space:pre">	</span>private static Bitmap viewToBitmap(View view, int viewWidth, int viewHeight) {
		view.layout(0, 0, viewWidth, viewHeight);
		view.buildDrawingCache();
		Bitmap bitmap = view.getDrawingCache();
		return bitmap;
	}



</pre><pre>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值