Android中如何实现矩形区域截屏

Android中如何实现矩形区域截屏

这篇文章主要介绍“Android中如何实现矩形区域截屏”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android中如何实现矩形区域截屏”文章能帮助大家解决问题。

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

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

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

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

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

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

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

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

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

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

直接看代码:

publicclassScreenCaptureActivityextendsActivity{privatestaticfinalStringTAG=ScreenCaptureActivity.class.getName();privateMediaProjectionManagermMediaProjectionManager;privateintREQUEST_MEDIA_PROJECTION=1;privateSimpleDateFormatdateFormat;privateStringpathImage;privateWindowManagermWindowManager;privateImageReadermImageReader;privateMediaProjectionmMediaProjection;privateintmResultCode;privateIntentmResultData;privateVirtualDisplaymVirtualDisplay;privateStringstrDate;privateintwindowWidth;privateintwindowHeight;privateStringnameImage;privateintmScreenDensity;@RequiresApi(api=Build.VERSION_CODES.LOLLIPOP)@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);mMediaProjectionManager=(MediaProjectionManager)getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);createVirtualEnvironment();startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(),REQUEST_MEDIA_PROJECTION);}@TargetApi(Build.VERSION_CODES.LOLLIPOP)@OverridepublicvoidonActivityResult(intrequestCode,intresultCode,Intentdata){if(requestCode==REQUEST_MEDIA_PROJECTION){if(resultCode!=Activity.RESULT_OK){return;}elseif(data!=null&&resultCode!=0){mResultCode=resultCode;mResultData=data;startVirtual();newHandler(Looper.getMainLooper()).postDelayed(newRunnable(){@Overridepublicvoidrun(){startCapture();}},100);}}}@RequiresApi(api=Build.VERSION_CODES.KITKAT)privatevoidcreateVirtualEnvironment(){dateFormat=newSimpleDateFormat("yyyy_MM_dd_hh_mm_ss");strDate=dateFormat.format(newDate());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();DisplayMetricsmetrics=newDisplayMetrics();mWindowManager.getDefaultDisplay().getMetrics(metrics);mScreenDensity=metrics.densityDpi;mImageReader=ImageReader.newInstance(windowWidth,windowHeight,0x1,2);//ImageFormat.RGB_565Log.i(TAG,"preparedthevirtualenvironment");}@TargetApi(Build.VERSION_CODES.LOLLIPOP)publicvoidstartVirtual(){if(mMediaProjection!=null){Log.i(TAG,"wanttodisplayvirtual");virtualDisplay();}else{Log.i(TAG,"startscreencaptureintent");Log.i(TAG,"wanttobuildmediaprojectionanddisplayvirtual");setUpMediaProjection();virtualDisplay();}}@TargetApi(Build.VERSION_CODES.LOLLIPOP)publicvoidsetUpMediaProjection(){mMediaProjection=mMediaProjectionManager.getMediaProjection(mResultCode,mResultData);Log.i(TAG,"mMediaProjectiondefined");}@TargetApi(Build.VERSION_CODES.LOLLIPOP)privatevoidvirtualDisplay(){mVirtualDisplay=mMediaProjection.createVirtualDisplay("screen-mirror",windowWidth,windowHeight,mScreenDensity,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mImageReader.getSurface(),null,null);Log.i(TAG,"virtualdisplayed");}@TargetApi(Build.VERSION_CODES.LOLLIPOP)privatevoidstartCapture(){strDate=dateFormat.format(newjava.util.Date());nameImage=pathImage+strDate+".png";Imageimage=mImageReader.acquireLatestImage();intwidth=image.getWidth();intheight=image.getHeight();finalImage.Plane[]planes=image.getPlanes();finalByteBufferbuffer=planes[0].getBuffer();intpixelStride=planes[0].getPixelStride();introwStride=planes[0].getRowStride();introwPadding=rowStride-pixelStride*width;Bitmapbitmap=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,"imagedatacaptured");//保存截屏结果,如果要裁剪图片,在这里处理bitmapif(bitmap!=null){try{FilefileImage=newFile(nameImage);if(!fileImage.exists()){fileImage.createNewFile();Log.i(TAG,"imagefilecreated");}FileOutputStreamout=newFileOutputStream(fileImage);if(out!=null){bitmap.compress(Bitmap.CompressFormat.PNG,100,out);out.flush();out.close();Intentmedia=newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);UricontentUri=Uri.fromFile(fileImage);media.setData(contentUri);this.sendBroadcast(media);Log.i(TAG,"screenimagesaved");}}catch(FileNotFoundExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}}}@TargetApi(Build.VERSION_CODES.LOLLIPOP)privatevoidtearDownMediaProjection(){if(mMediaProjection!=null){mMediaProjection.stop();mMediaProjection=null;}Log.i(TAG,"mMediaProjectionundefined");}}

第三步、对截图进行裁剪

根据***步得到的截图区域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;intcut_width=Math.abs(mRect.left-mRect.right);intcut_height=Math.abs(mRect.top-mRect.bottom);if(cut_width>0&&cut_height>0){BitmapcutBitmap=Bitmap.createBitmap(bitmap,mRect.left,mRect.top,cut_width,cut_height);}

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

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

带NavigationBar使用系统截图的结果

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

int[]pixel=newint[width];bitmap.getPixels(pixel,0,width,0,0,width,1);intleftPadding=0;intrightPadding=width;for(inti=0;i<pixel.length;i++){if(pixel[i]!=0){leftPadding=i;break;}}for(inti=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,就会在左边也产生框,所以才用了上面的方法。

关于“Android中如何实现矩形区域截屏”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注恰卡编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

发布于 2022-04-11 21:16:16
收藏
分享
海报
0 条评论
24
上一篇:Android中如何利用Input子系统监听线程的启动 下一篇:android中事件分发机制怎么实现
目录

    推荐阅读

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码