android 开发 矩形截屏插件,Android 上如何实现矩形区域截屏

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

晚截图可以分成三步:

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

调用系统接口截屏

对截图进行裁剪

效果图如下:

c4be3af222c44d018c81cc3fb72aa2d4.png

矩形区域截屏

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

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

手指拖动形成矩形区域;

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

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

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

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

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

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

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

直接看代码:

publicclass ScreenCaptureActivity extends Activity {    privatestaticfinal String TAG = ScreenCaptureActivity.class.getName();    private MediaProjectionManager mMediaProjectionManager;    privateintREQUEST_MEDIA_PROJECTION = 1;    private SimpleDateFormat dateFormat;    private String pathImage;    private WindowManager mWindowManager;    private ImageReader mImageReader;    private MediaProjection mMediaProjection;    privateintmResultCode;    private Intent mResultData;    private VirtualDisplay mVirtualDisplay;    private String strDate;    privateintwindowWidth;    privateintwindowHeight;    private String nameImage;    privateintmScreenDensity;    @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

publicvoid onActivityResult(intrequestCode,intresultCode, Intent data) {        if (requestCode == REQUEST_MEDIA_PROJECTION) {            if (resultCode != Activity.RESULT_OK) {return;

} elseif (data !=null&& resultCode != 0) {

mResultCode = resultCode;

mResultData = data;

startVirtual();                new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {                    @Override

publicvoid 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)    publicvoid 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)    publicvoid 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();        intwidth = image.getWidth();intheight = image.getHeight();        final Image.Plane[] planes = image.getPlanes();        final ByteBuffer buffer = planes[0].getBuffer();intpixelStride = planes[0].getPixelStride();introwStride = planes[0].getRowStride();introwPadding = 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

mRect.left= 0;    if (mRect.right

mRect.right= 0;    if (mRect.top

mRect.top= 0;    if (mRect.bottom 

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) {

Bitmap cutBitmap = Bitmap.createBitmap(bitmap, mRect.left, mRect.top, cut_width, cut_height);

}

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

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

5f5a633edbbb11d16e2ff5d66d3b17d0.png

带NavigationBar使用系统截图的结果

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

int[] pixel=newint[width];

bitmap.getPixels(pixel,0,width ,0,0,width,1);intleftPadding=0;intrightPadding=width;for(inti=0;i

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);

处理后的截图如下:

edbc7e69dd08acaebd804198b0b4e2a3.png

取得截图结果的内容部分

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

完整代码可以参考 Bigbang 项目的MarkSizeView类、ScreenCaptureActivity类和ScreenCapture类。

【编辑推荐】

【责任编辑:枯木 TEL:(010)68476606】

点赞 0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/344290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java可选参数

在Java类中设计方法时,某些参数对于其执行而言可能是可选的。 无论是在DTO,胖模型域对象还是简单的无状态服务类中,可选方法参数都是常见的。 从本文中, 您将学习如何在Java中处理可选参数 。 我们将专注于常规方法,带…

计算机发送到桌面快捷方式,windows7添加到桌面快捷方式无故消失!

您好,Windows 7设计者在Windows 7中所添加的设计。在默认情况下,只要System Maintenance troubleshooter(系统故障维护,以下简称SMT)检测到桌面的快捷方式已经无效了,将会自动将其删除。每周,SMT(系统故障维护)都会对操…

Java:汇总堆外数据

探索如何以最小的垃圾收集影响和最大的内存利用率创建堆​​外聚合。 使用Java Map,List和Object创建大型聚合通常会产生大量堆内存开销。 这也意味着,一旦聚合超出范围,垃圾收集器将必须清理这些对象。 阅读这篇简短的文章,了解…

java中属性外部化_用Java可外部化

java中属性外部化在理解Externalizable接口之前,您需要了解序列化。您可以在java中的序列化上阅读有关序列化的更多信息。 Java提供了一种称为序列化的机制,以按字节的有序或字节序列的形式持久化Java对象,其中包括对象的数据以及有关对象的…

在您的Maven-Fu包中增加了一些东西

Apache Maven很简单,但是功能非常强大。 使用一些技巧,您可以大大简化和优化您的开发经验。 处理多个非托管模块 假设您有一个主项目A提供了两个实用程序模块foo和bar ,另一个项目B A了foo和bar 。 在使用B ,您意识到需要偶尔对…

ci 邮件 html模板,CI Email类发邮件

发邮件代码详情private function _send_mail($data) {//附件一,名称参数编码转换if(!empty($data[resume_name])){$file_name iconv(UTF-8,GB2312,$data[file_name]);}//附件二,名称参数编码转换if(!empty($data[resume_name])){$resume_name iconv(UT…

Java安全动画

总览 自从JDK 1.2中引入安全沙箱模型以及JDK提供的安全API的发展以来,Java安全就一直是一个复杂的话题。 并发实用程序也观察到类似的问题,并且开发了一种名为Java Concurrent Animated的工具,目的是通过有趣而有趣的方式降低进入这些实用程序…

在计算机网络系统的远程通信中,在计算机网络系统的远程通信中,通常采用的传输技术是...

摘要:算机体系体系模板模板最适宜采用的合钢是组。系统信中民主命叙主义关于革命以下义革误的和社会主述错是(。程通常采传输不属民主主义济纲的三大经以下于新领的是(。...算机体系体系模板模板最适宜采用的合钢是组。网络不属特殊国无级自的是产阶以下于中有的优点…

ajax div 赋值重新渲染_优化向:单页应用多路由预渲染指南

前言Ajax 技术的出现,让我们的 Web 应用能够在不刷新的状态下显示不同页面的内容,这就是单页应用。在一个单页应用中,往往只有一个 html 文件,然后根据访问的 url 来匹配对应的路由脚本,动态地渲染页面内容。单页应用在…

fpga运算服务器_一张图了解CPU、GPU、ASIC、FPGA性能、功耗效率、灵活性

​CPU:中央处理器(Central Processing Unit,CPU):通用芯片,主要生产厂家如intel、AMD等,用于PC、服务器等领域。CPU作为通用芯片,可以用来做很多事情,灵活性最高&#xf…

aspen变压吸附塔_空压机科普:吸附式干燥机的结构和原理

精彩内容本文以主流的“变压吸附式”干燥机为例进行讲解。“吸附”原理一致,“脱附再生”流程有所区别。从而大致形成以下几种常见类型:●无热吸附式——使用一部分经过干燥后的压缩空气,经降压后吹扫吸附剂,实现吸附剂“再生”&a…

小学计算机管理,小学计算机室管理制度

小学计算机室管理制度 (2页)本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!19.90 积分芹菜小学计算机室制度1、计算机室由上电脑课老师负责管理。2、计算机室是进行电脑技术学习和操作的场所&#xff…

异形3×3魔方还原教程_【初级篇】(四)最简单的三阶魔方入门教程——中层还原...

本系列教程适合刚刚接触魔方,又比较有好奇心,是为渴望学会还原魔方,又不想死记公式的人准备的。全部教程只使用三种公式,还原过程以理解为主,公式为辅。第四部分 中层棱块还原4.1 预览中层棱块还原后的效果中层还原以后…

吞吐量-Corda的故事

我最近开展了一个针对特定用例的Corda性能项目。 这个项目的结果使我们在170多个节点的网络上一天之内处理了1.15亿个请求。 此外,Corda每秒能够处理6300个请求,确认满足了网络的最高要求。 迄今为止,这是迄今为止已部署的最大的Corda网络&am…

httpurlconnect设置中文参数_数控三菱CNC机床参数的设置及报警解除!

数控三菱CNC的硬件连接检查与设置执行完毕向系统送电后,显示器上的READY绿灯仍然不亮。而且在〔诊断〕――〔报警〕 画面上显示很多报警内容,哪些是开机时必须设置的呢?又如何解除故障报警呢?1.开机参数1.1 基本参数的设置原装系统…

计算机如何更新苹果系统,苹果系统怎么更新_苹果电脑mac如何更新升级系统-win7之家...

苹果电脑跟windows系统一样,也是会在发布之后不断的推送新版本让用户们进行升级,不仅可以修复bug还可以增加新功能,不过很多用户可能都会有一个疑问,就是苹果系统怎么更新呢?方法并不难,本文给大家讲述一下…

手术步骤_近视飞秒激光手术和传统Lasik手术比较

传统LasikLASIK手术操作时分为两个步骤:第一个步骤医生需要制作一个角膜瓣;第二个步骤是掀开角膜瓣,以准分子激光雕琢角膜,进行视力矫正,雕琢完毕后将角膜瓣复位即手术完成。传统的角膜制瓣是用机械式的设备与一个微型…

jenkins部署java_在Window上使用Jenkins自动部署和上传快照Java工件

jenkins部署java这篇文章将展示如何使用Jenkins Continuous Integration自动执行Java Web应用程序(使用MYSQL DB和基于Hibernate ORM在基于REST的Jersey2 Spring环境中开发的学生申请应用程序)的部署过程-生成项目,运行单元测试,上…

苹果电脑怎么更换计算机模式,图文详解苹果电脑如何切换成windows系统

苹果电脑默认安装的是Mac系统,有的人很喜欢,有一部分人却怎么都用不习惯,觉得windows系统用起来比较顺手。为了能提高办公效率,给苹果电脑安装双系统,那么有什么办法能将苹果电脑切换成windows系统?方法当然…

input内的字体颜色_嘉兴市硅胶喷涂颜色油订制

嘉兴市硅胶喷涂颜色油订制,博越硅胶服务惠万家,欢迎惠顾。嘉兴市硅胶喷涂颜色油订制, 而它配合硅胶原材制作时是按照相应的比例来进行分配在加上硫化剂的配合才能够得到制作产品的原材料,色母的性能选择也影响着一个产品的性能&am…