当前位置: 移动技术网 > IT编程>数据库>MSSQL > Android实现矩形区域截屏的方法

Android实现矩形区域截屏的方法

2017年12月08日  | 移动技术网IT编程  | 我要评论

只因爱你by欲语还休,战国basara3宴,信宜市玉都风情网

对屏幕进行截屏并裁剪有两种方式:早截图和晚截图。早截图,就是先截取全屏,再让用户对截取到的图片进行修改;与之相对的,晚截图,就是先让用户在屏幕上划好区域,再进行截图和裁剪。其实两者并没有什么太大的区别,这篇就说说怎么实现晚截图。

晚截图可以分成三步:

1. 在屏幕上标出截图的矩形区域

2. 调用系统接口截屏

3. 对截图进行裁剪

效果图如下:

矩形区域截屏

第一步、在屏幕上标识出截图区域

首先确定标识截图区域所需要的功能:

1. 手指拖动形成矩形区域;

2. 可以拖动已经划好的矩形区域进行移动;

3. 可以拖动矩形区域的边框调整大小;

4. 选择完成以后,有“确认”和“取消”功能,“确认”时可以获得选取的区域位置。需要注意的是,按钮的位置应该能够自适应,比如选框几乎占据全屏的情况下,应该把按钮放到选框内部。

最简单的方式就是写一个自定义view,根据touch的位置执行不同的功能即可。实现很简单,只要细心把每一种状态就行,代码请看bigbang项目的marksizeview类。

第二步、调用系统接口截屏

截屏必须在activity中进行,因为需要调用startactivityforresult()。不过也可以把mmediaprojectionmanager传到service中进行后续处理。

还要注意的是activity本身在截屏的时候应该是透明的,不能对要截取得内容有影响。

直接看代码:

public class screencaptureactivity extends activity {
 private static final string tag = screencaptureactivity.class.getname();
 private mediaprojectionmanager mmediaprojectionmanager;
 private int request_media_projection = 1;
 private simpledateformat dateformat;
 private string pathimage;
 private windowmanager mwindowmanager;
 private imagereader mimagereader;
 private mediaprojection mmediaprojection;
 private int mresultcode;
 private intent mresultdata;
 private virtualdisplay mvirtualdisplay;
 private string strdate;
 private int windowwidth;
 private int windowheight;
 private string nameimage;
 private int mscreendensity;
 @requiresapi(api = build.version_codes.lollipop)
 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 mmediaprojectionmanager = (mediaprojectionmanager) getapplication().getsystemservice(context.media_projection_service);
 createvirtualenvironment();
 startactivityforresult(mmediaprojectionmanager.createscreencaptureintent(), request_media_projection);
 }
 @targetapi(build.version_codes.lollipop)
 @override
 public void onactivityresult(int requestcode, int resultcode, intent data) {
 if (requestcode == request_media_projection) {
  if (resultcode != activity.result_ok) {
  return;
  } else if (data != null && resultcode != 0) {
  mresultcode = resultcode;
  mresultdata = data;
  startvirtual();
  new handler(looper.getmainlooper()).postdelayed(new runnable() {
   @override
   public void run() {
   startcapture();
   }
  },100);
  }
 }
 }
 @requiresapi(api = build.version_codes.kitkat)
 private void createvirtualenvironment() {
 dateformat = new simpledateformat("yyyy_mm_dd_hh_mm_ss");
 strdate = dateformat.format(new date());
 pathimage = environment.getexternalstoragedirectory().getpath() + "/pictures/";
 nameimage = pathimage + strdate + ".png";
 mmediaprojectionmanager = (mediaprojectionmanager) getapplication().getsystemservice(context.media_projection_service);
 mwindowmanager = (windowmanager) getapplication().getsystemservice(context.window_service);
 windowwidth = mwindowmanager.getdefaultdisplay().getwidth();
 windowheight = mwindowmanager.getdefaultdisplay().getheight();
 displaymetrics metrics = new displaymetrics();
 mwindowmanager.getdefaultdisplay().getmetrics(metrics);
 mscreendensity = metrics.densitydpi;
 mimagereader = imagereader.newinstance(windowwidth, windowheight, 0x1, 2); //imageformat.rgb_565
 log.i(tag, "prepared the virtual environment");
 }
 @targetapi(build.version_codes.lollipop)
 public void startvirtual() {
 if (mmediaprojection != null) {
  log.i(tag, "want to display virtual");
  virtualdisplay();
 } else {
  log.i(tag, "start screen capture intent");
  log.i(tag, "want to build mediaprojection and display virtual");
  setupmediaprojection();
  virtualdisplay();
 }
 }
 @targetapi(build.version_codes.lollipop)
 public void setupmediaprojection() {
 mmediaprojection = mmediaprojectionmanager.getmediaprojection(mresultcode, mresultdata);
 log.i(tag, "mmediaprojection defined");
 }
 @targetapi(build.version_codes.lollipop)
 private void virtualdisplay() {
 mvirtualdisplay = mmediaprojection.createvirtualdisplay("screen-mirror",
  windowwidth, windowheight, mscreendensity, displaymanager.virtual_display_flag_auto_mirror,
  mimagereader.getsurface(), null, null);
 log.i(tag, "virtual displayed");
 }
 @targetapi(build.version_codes.lollipop)
 private void startcapture() {
 strdate = dateformat.format(new java.util.date());
 nameimage = pathimage + strdate + ".png";
 image image = mimagereader.acquirelatestimage();
 int width = image.getwidth();
 int height = image.getheight();
 final image.plane[] planes = image.getplanes();
 final bytebuffer buffer = planes[0].getbuffer();
 int pixelstride = planes[0].getpixelstride();
 int rowstride = planes[0].getrowstride();
 int rowpadding = rowstride - pixelstride * width;
 bitmap bitmap = bitmap.createbitmap(width + rowpadding / pixelstride, height, bitmap.config.argb_8888);
 bitmap.copypixelsfrombuffer(buffer);
 bitmap = bitmap.createbitmap(bitmap, 0, 0, width, height);
 image.close();
 log.i(tag, "image data captured");
 //保存截屏结果,如果要裁剪图片,在这里处理bitmap
 if (bitmap != null) {
  try {
  file fileimage = new file(nameimage);
  if (!fileimage.exists()) {
   fileimage.createnewfile();
   log.i(tag, "image file created");
  }
  fileoutputstream out = new fileoutputstream(fileimage);
  if (out != null) {
   bitmap.compress(bitmap.compressformat.png, 100, out);
   out.flush();
   out.close();
   intent media = new intent(intent.action_media_scanner_scan_file);
   uri contenturi = uri.fromfile(fileimage);
   media.setdata(contenturi);
   this.sendbroadcast(media);
   log.i(tag, "screen image saved");
  }
  } catch (filenotfoundexception e) {
  e.printstacktrace();
  } catch (ioexception e) {
  e.printstacktrace();
  }
 }
 }
 @targetapi(build.version_codes.lollipop)
 private void teardownmediaprojection() {
 if (mmediaprojection != null) {
  mmediaprojection.stop();
  mmediaprojection = null;
 }
 log.i(tag, "mmediaprojection undefined");
 }
}

第三步、对截图进行裁剪

根据第一步得到的截图区域mrect对第二步中得到的截屏结果bitmap进行裁剪:

if (mrect != null) {
 if (mrect.left < 0)
 mrect.left = 0;
 if (mrect.right < 0)
 mrect.right = 0;
 if (mrect.top < 0)
 mrect.top = 0;
 if (mrect.bottom < 0)
 mrect.bottom = 0;
 int cut_width = math.abs(mrect.left - mrect.right);
 int cut_height = math.abs(mrect.top - mrect.bottom);
 if (cut_width > 0 && cut_height > 0) {
 bitmap cutbitmap = bitmap.createbitmap(bitmap, mrect.left, mrect.top, cut_width, cut_height);
}

需要注意的是,在调用系统截屏功能的时候,如果手机有navigationbar(虚拟导航栏),windowheight的取值就是不包括navigationbar的高度的,如果不进行调整,就会导致截屏被压缩。如何获取屏幕的真实高度,可以参考android如何判断navigationbar是否显示(获取屏幕真实的高度)

而且navigationbar还会导致截屏的结果出现边框,边框的颜色是透明的,原因是第二步代码中的rowpadding!=0,截屏如下图所示:

带navigationbar使用系统截图的结果

那么如果我们想要对截图的结果进行保存或者裁剪,就必须要去除边框,找出真正的内容区域,也就是在第一个不透明的像素和最后一个不透明像素之间的内容,然后才能对得到的区域进行第三步的裁剪,代码如下:

int[] pixel=new int[width];
bitmap.getpixels(pixel,0,width ,0,0,width,1);
int leftpadding=0;
int rightpadding=width;
for (int i=0;i<pixel.length;i++){
 if (pixel[i]!=0){
 leftpadding=i;
 break;
 }
}
for (int i=pixel.length-1;i>=0;i--){
 if (pixel[i]!=0){
 rightpadding=i;
 break;
 }
}
bitmap=bitmap.createbitmap(bitmap,leftpadding, 0, rightpadding-leftpadding, height);

处理后的截图如下:

取得截图结果的内容部分

你可能会觉得既然是rowpadding!=0导致出现边框,而且边框只在右边,为什么不直接把右边rowpadding宽度的内容截掉呢?其实是因为如果不调整windowheight,就会在左边也产生框,所以才用了上面的方法。

完整代码可以参考bigbang项目的marksizeview类、screencaptureactivity类和screencapture类。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网