对屏幕进行截屏并裁剪有两种方式:早截图和晚截图,对于早截图和晚截图的概念大家通过本文详解学习。本文重点给大家介绍android实现矩形区域截屏的方法,需要的朋友参考下

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

晚截图可以分成三步:

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,截屏如下图所示:

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

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类。

原文链接:http://blog.csdn.net/l465659833/article/details/54136327

Android实现自定义曲线截屏,Android实现矩形区域截屏的方法相关推荐

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

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

  2. Android上如何实现矩形区域截屏

    本文转载http://www.jianshu.com/p/0462dae4c808 转载注明出处:简书-十个雨点 对屏幕进行截屏并裁剪有两种方式:早截图和晚截图.早截图,就是先截取全屏,再让用户对截取 ...

  3. android自定义曲线控件,Android自定义view进阶-- 神奇的贝塞尔曲线

    上一篇介绍了自定义view需要知道的基本函数.新开一篇献给借给我vpn的深圳_奋斗小哥. 转载请注明出处:http://blog.csdn.net/wingichoy/article/details/ ...

  4. android 实现自定义监听接口,Android在自定义类中实现自定义监听器方式

    Android在自定义类中实现自定义监听器方式 发布时间:2020-08-31 06:19:39 来源:脚本之家 阅读:203 作者:Simon_Qi 监听器可以说是Android开发中最常用的东西之 ...

  5. Android之自定义view引用xml,Android自定义View在XML中映射错误

    Android开发中我们经常会遇到自定义View地址映射错误的情况,现将遇到的情况做下总结: //Android Studio的异常信息 Error inflating class 1.直接像下面这样 ...

  6. JavaScript 触发浏览器页面全屏,某div区域全屏

    JavaScript Fullscreen API:全屏操作 全屏API可以控制浏览器的全屏显示,让一个Element节点(以及子节点)占满用户的整个屏幕.目前各大浏览器的最新版本都支持这个API(包 ...

  7. Android实现自定义曲线截屏,Android实现价格走势自定义曲线图

    本文是引用开源图表库框架 MPAndroidChart的LineChart 1.需求: (1)动态添加RadioButton,点击改变下面的LineChart数据 (2)LineChart绘制价格走势 ...

  8. Android实现自定义曲线截屏,Android实现截屏和截长图功能的各种方法

    /** * 截屏 * * @param activity * @return */ public static Bitmap activityShot(Activity activity) { /*获 ...

  9. android自定义曲线控件,Android自定义折线图(可拖动显示)

    废话不多说先上图咯 图一 至于怎么做呢 咱们可以先获取下折线图数据分析一波 { "code": 200, "message": "", &q ...

  10. Android m 自定义下拉菜单,Android实现动画效果的自定义下拉菜单功能

    我们在购物APP里面设置收货地址时,都会有让我们选择省份及城市的下拉菜单项.今天我将使用Android原生的 Spinner 控件来实现一个自定义的下拉菜单功能,并配上一个透明渐变动画效果. 要实现的 ...

最新文章

  1. usaco Preface Numbering 序言页码
  2. IPSec ports should be allowed
  3. 【ArcGIS风暴】最牛逼空间数据批处理神器来了:用户自定义工具箱GeoStorm.tbx
  4. sql中的while循环_SQL While循环:了解SQL Server中的While循环
  5. 自治系统中单个路由表的构造
  6. OpenCV源码解析之动态内存管理CvMemStorage与CvSeq
  7. 使用rufus-3.8 制作启动U盘安装Windows severs 2019
  8. laravel 框架使用hdjs 实现富文本编辑器功能
  9. 制作window11系统U盘启动盘
  10. Shopee平台发布针对疫情政策的通知
  11. 5.2 lilyglyphs包
  12. memcached(十三)注意事项
  13. 计算机在职研究生的详细介绍
  14. 亚马逊产品违反受限政策,亚马逊受限产品恢复在售
  15. 31道Java面试题,java冒泡排序详解
  16. 关于框架,到底什么是框架?
  17. 在linux4.15 移植设备树到JZ2440
  18. OCX控件全屏、恢复
  19. 解决p标签自动换行文字两端不对齐问题
  20. altera fpga 型号说明_ALTERA的FPGA命名规则(转载)

热门文章

  1. 惠普打印机故障代码_惠普打印机出现故障怎么办
  2. keil(MDK) 5官方下载教程
  3. ps4手柄android ppsspp,求助,ppsspp模拟器能用ps4手柄吗
  4. 2022-08-22 步进电机驱动程序
  5. MathType输入花体字
  6. 微信小程序60s倒计时
  7. 网站微信扫码登录回调不跳转问题
  8. 数仓OLAP(一)--即席查询 Kylin
  9. 专题开发十三:JEECG微云高速开发平台-附录
  10. VS QT进行相机镜头控制软件二次开发