Google原生Android系统到目前为止均没有长截屏这一功能,而对于用户而言,这是一个非常实用的功能,如聊天记录,新闻页面等较长的页面想通过一张图片的形式保存起来.好在国内主流手机厂商均已实现了该功能,接下来聊聊我们长截屏的实现原理.

长截屏原理概述:

我们简单的把一个屏幕分成三分,上中下,中间区域最大,中间区域也就是滑动区域;长截屏开始,我们截取顶部的图片保存到集合中,截取长度如下,然后每次滑动图片前截取中间部分图片保存到集合中,也就是滑动多少次就会有多少张中间区域图片,最后保存时,截取底部图片保存到集合中;随后把集合中的图片拼接起来就完成了长截屏

中间部分为滑动区域,也就是我们模拟手指在屏幕上滑动一个指定长度,这个长度也就是中间图片的长度.模拟滑动代码如下:

    // 模拟Down事件MotionEvent tempDown = MotionEvent.obtain(downTime, eventTime, 0, toX, toY, 0);tempDown.setSource(4098);InputManager.getInstance().injectInputEvent(tempDown, Integer.valueOf(2));// 模拟Move事件MotionEvent tempMove = MotionEvent.obtain(downTime, eventTime, 2, toX, toY, 0);tempMove.setSource(4098);InputManager.getInstance().injectInputEvent(tempMove, Integer.valueOf(2));// 模拟Up事件MotionEvent tempUP = MotionEvent.obtain(downTime, eventTime, 1, toX, toY, 0);tempUP.setSource(4098);InputManager.getInstance().injectInputEvent(tempUP, Integer.valueOf(2));

injectInputEvent方法为@hide,没环境调用的可以通过反射调用:

    try {Class<?> ClassInputManager = Class.forName("android.hardware.input.InputManager");Method[] methods = ClassInputManager.getMethods();Method methodGetInstance = null;Method methodInjectInputEvent = null;Method method = methods[0];for (int i = 0; i < methods.length; i++) {method = methods[i];if (method.getName().equals("getInstance")) {methodGetInstance = method;}if (method.getName().equals("injectInputEvent")) {methodInjectInputEvent = method;}}Object mInstance = methodGetInstance.invoke(ClassInputManager, new Object[0]);long downTime = SystemClock.uptimeMillis();long eventTime = SystemClock.uptimeMillis();float y = fromY;if (fromY > toY) {// action downMotionEvent eventDown = MotionEvent.obtain(downTime, eventTime, 0, fromX, y, 0);eventDown.setSource(4098);Object[] arrayOfObject2 = new Object[2];arrayOfObject2[0] = eventDown;arrayOfObject2[1] = Integer.valueOf(2);methodInjectInputEvent.invoke(mInstance, arrayOfObject2);eventDown.recycle();}// action moveMotionEvent eventMove2 = MotionEvent.obtain(downTime, eventTime, 2, toX, y, 0);eventMove2.setSource(4098);Object[] objMove2 = new Object[2];objMove2[0] = eventMove2;objMove2[1] = Integer.valueOf(2);methodInjectInputEvent.invoke(mInstance, objMove2);eventMove2.recycle();// action upMotionEvent eventUp = MotionEvent.obtain(downTime, eventTime, 1, toX, toY, 0);eventUp.setSource(4098);Object[] objUp = new Object[2];objUp[0] = eventUp;objUp[1] = Integer.valueOf(2);methodInjectInputEvent.invoke(mInstance, objUp);eventUp.recycle();} catch (Exception e) {e.printStackTrace();}

细节(核心):

以上方式完成长截屏理论上没有问题,但是还有一个细节,也是核心;比如每次模拟滑动10厘米,但是最后一次滑动已经接近底部了,实际距离不到10厘米,因此最后一张图片的实际长度我们无法知道.(通俗的说是我们默认滑动10厘米,但是约2厘米的时候到底划不动了,而默认截取的长度还是10厘米,因此我们需要去掉多余的8厘米长度图片)

左边为中间区域倒数第二张图片 右边为中间区域倒数第一张图片:

如上图所示,蓝色矩形部分为最后一张图片的实际滑动距离,红叉区域由于滑动到底,滑不动导致的重叠部分.

因此,我们需要截取最后一张图的实际长度,如下图:

怎么样去掉重叠部分的图片?

如下图,截取上述两张图片的左侧区域(2号图的左下红色区域,1号图的左侧红色区域),接下进行图片匹配裁剪,排除部分滑动控件有SeekBar的情况.

如上图,获取裁减后的图2,从底部开始,取一个像素高的图片,所得图片的每个像素颜色转为int值,存入pixels2,函数如下:

target.getPixels(pixels2, 0, this.mCropW, 0, (target.getHeight() - 1), this.mCropW, 1);

从底部开始依次遍历图1一个像素为高度的图片,同理获取所得图片的每个像素颜色转为int值,存入pixels1;如果匹配,将匹配的图片高度存入lineList集合

    for (int i = 0; i < source.getHeight(); i = i + 1) {source.getPixels(pixels1, 0, this.mCropW, 0, i, this.mCropW, 1);if (Arrays.equals(pixels2, pixels1)) {lineList.add(Integer.valueOf(i));}}

由于我们取的是一个像素为高度的样本图片,因此匹配到相等的情况比较常见.

随后,遍历lineList,对匹配相识度最高的图片的高度进行裁剪.

匹配方法和上述方法类似,遍历裁剪后的图2的高度,遍历累计增加一个高度;图1裁剪后的图片取底部一个像素的高度和图2遍历的高度取一个像素的高度对比,如果相等记录一下,随后依次取倒数第二个像素开始的一个像素的高度进行对比,通过总次数和匹配相等的次数算是一个匹配概率.最后取概率最高的lineList中的高度.

    private float compareLastBitmap(Bitmap bitmap2, Bitmap bitmap1, int index) {int[] pixels_target = new int[mCropW];int[] pixels_source = new int[mCropW];int count = 0;int height = Math.min((bitmap2.getHeight() - 1), index);height = Math.max(height, 1);for (int i = 0x0; i < height; i = i + 1) {// 倒数第二张图片的底部  一个像素高度的图片  (遍历累计减少高度)bitmap2.getPixels(pixels_target, 0, mCropW, 0, ((bitmap2.getHeight() - 1) - i), mCropW, 1);// 最后一张图片  指定高度开始(遍历累计减少高度)   一个像素高度的图片bitmap1.getPixels(pixels_source, 0, mCropW, 0, (index - i), mCropW, 1);if (Arrays.equals(pixels_target, pixels_source)) {count = count + 1;}}return (float) count / (float) height;}// 取概率最高的lineList中的高度int line_index = -1;for (int i = 0; i < lineList.size(); i = i + 1) {float percent = compareLastBitmap(target, source, lineList.get(i).intValue());if (percent == 1.0) {list.add(lineList.get(i).intValue());if (list.size() > 80) {    // 底部图片相同导致size过大循环过长的情况line_index = lineList.get(i).intValue();list.clear();break;}}if (percent > bigger) {bigger = percent;line_index = lineList.get(i).intValue();}}

貌似找到匹配度为100%然后对对应图片高度进行裁剪就完了,但是匹配度为100%情况有时候会出现多个,这是为什么?

原来当一张图片中 相似的部分很多的时候(例如图片中重复空白区域很多),我们每次取一个像素进行对比很容易出现匹配度为100%的情况,因此接下我们还得为这种情况进行处理.

通过递归的方式每次累计增加样本图片的高度(之前每次都是取一个像素为高度,递归累计增加图片的高度进行匹对)

    // space为取对比图片的高度为几个像素private int compare(Bitmap target, Bitmap source, ArrayList<Integer> list, int space) {int count = 0;int line_height = 0;for (int j = 0; j < list.size(); j++) {int[] pixels_target = new int[mCropW * space];int[] pixels_source = new int[mCropW * space];line_height = list.get(j).intValue();if ((line_height - space) < 0) {break;}if ((target.getHeight() - space) < 0) {break;}// 取space高度的样本对两张图片进行比较,遍历累计增加样本图片的高度target.getPixels(pixels_target, 0, this.mCropW, 0, (target.getHeight() - space), this.mCropW, space);source.getPixels(pixels_source, 0, this.mCropW, 0, line_height - space, this.mCropW, space);if (Arrays.equals(pixels_target, pixels_source)) {count++;}}// 递归增加图片高度进行对比if (count > 1) {return compare(target, source, list, ++space);}return line_height;}

获取需要裁剪的高度后,裁剪图片,裁剪后的图片如下:

随后将如上图片替换到图片集合中最后一张图片(有重复区域的图片).

最后将如下底部的图片保存到集合,然后进行图片拼接,完成长截屏.

图片拼接: 首先创建一个 所有集合中图片长之和为长,屏宽为宽度的图片;遍历集合,依次将集合中的图片按坐标绘制到刚刚所创建的图片上

Android屏幕截图实现方式 & 系统截屏源码分析和三指截屏

Android屏幕录制源码Demo下载

Android长截屏(滚动截屏)实现原理相关推荐

  1. 限免|iOS长截图工具 滚动截屏

    使用录屏的方式来实现长截图的功能,不需要再一张张截图拼接,不限应用,无论是微信聊天还是公众号文章都可以使用滚动截屏. 软件名:滚动截屏-无需拼接快速生成长截图 优点:无内购,无广告 缺点:会有一些不足 ...

  2. Android RecyclerView 横屏禁用滚动/竖屏开启滚动

    最近项目在做瀑布流 ,然后整体我是用RecyclerView 做的 ,而且每个item 里面会有个播放器.我们的需求是这个播放器可以全屏展开,但是如果全屏展开 ,不能让RecyclerView 滚动. ...

  3. iphone长截图哪个软件好_亲身体验过13款滚动截屏App,谁才是最好用的iPhone长截屏工具?...

    (☝聪明的人都会星标我☝) 上次我们分享了关于手机录屏怎么只录入手机系统声音而不录入外界声音,有小伙伴留言"苹果手机怎么长截屏?",必须安排一波! 与苹果手机相比,安卓手机想要长截 ...

  4. android长截屏代码,android长截屏原理及实现代码

    android长截屏原理及实现代码 发布时间:2020-08-31 06:55:16 来源:脚本之家 阅读:158 作者:Android笔记 小米系统自带的长截屏应该很多人都用过,效果不错.当长截屏时 ...

  5. android 截长图 方法,Android实现截屏与截长图功能

    本文实例为大家分享了Android实现截屏与截长图功能展示的具体代码,供大家参考,具体内容如下 Demo在GitHub的地址:ScreenShoot 在Android开发中,有时候会遇到需要截屏分享到 ...

  6. ios截屏功能html,滚动截屏APP - iPhone上的长截图工具

    话说长截图功能也算是一种刚需了,如今安卓好多手机系统都会自带此功能.很难想象的是,安卓手机标配的「长截图」功能,对果粉来说是多么的奢侈.iPhone没有自带的长截图功能,只能借助第三方APP,比如Ta ...

  7. Android实现截屏和截长图功能的几种方法

    一般情况下各种型号的手机都会有自带的截屏功能,也会有诸如"开关机键+音量键"的截屏快捷键,只要手机是亮屏状态,都会将手机屏幕的可视区域(包含状态栏)全部截取下来. 如果开发中想要调 ...

  8. Android 实现截屏和截长图功能的几种方法

    欢迎大家关注我的公众号:**牛角尖尖上起舞** 一般情况下各种型号的手机都会有自带的截屏功能,也会有诸如"开关机键+音量键"的截屏快捷键,只要手机是亮屏状态,都会将手机屏幕的可视区 ...

  9. Android实现截屏和截长图功能的各种方法

    微信好友或者朋友圈的分享,可以是普通的截图分享,也可以是截取长图的分享,甚至还会有需求让你拼上生成的二维码和logo图片,下面我们直接来看看这些方法的使用: 先说一下拼接三张不同的图片后有黑色背景的解 ...

  10. Snagit滚动截屏实现长pdf(长图)拆分

    Snagit的自定义滚动截屏模式,可用来实现长pdf拆分.

最新文章

  1. 【自然语言处理】正向、逆向、双向最长匹配算法的 切分效果与速度测评
  2. 苹果挂端口方法_一招教你,让光猫四个端口既能上网又能IPTV,不用再区分端口...
  3. python学多久可以接单-零基础小白多久能学会python
  4. c语言编写源程序内容,编程(C语言源程序代码)讲述.doc
  5. python 课程设计 夏敏捷_Python课程设计(微课视频版21世纪高等学校通识教育规划教材)/计算机技术入门丛书...
  6. Exchange安装过程中经常遇到的服务器需要重启问题
  7. 贪心+优先队列之更改优先级-hdu1896
  8. git 解决fatal: Not a git repository
  9. html5个人简历代码模板,个人简历HTML模板
  10. 使用Python face_recognition 人脸识别 - 12 人脸图片1-N比对
  11. 最小生成树算法之Kruskal算法
  12. 大佬们抖音带货流水都过亿 普通人有什么抖音变现的好方式
  13. 论文那些事—ZOO: Zeroth Order Optimization Based Black-box Attacks
  14. 浅谈支付宝第三方支付
  15. 星起航:跨境电商行业卖家可利用新技术打造成熟供应链
  16. android极光推送判断消息,通过极光推送给Android所有用户发送推送消息
  17. matlab中图形框布局调整,MATLAB:正确调整图形大小
  18. tensorflow 猫狗识别 数据增强
  19. Excel数据 SQL SERVER
  20. nft数字藏品如何卖出去(浅谈数字藏品的合规交易流程

热门文章

  1. uniwebview按钮被无形遮挡问题
  2. The NMEA 0183 Protocol
  3. win11还原win10磁贴方法ExplorerPatcher,替代Start 11、StartALLBack(开源免费~)
  4. Python >>> 基于UDP 协议的实时网络视频传输
  5. 如何在Excel 2007中创建数据透视表
  6. 怎样学好模拟集成电路设计?
  7. iOS上架app store下载步骤
  8. 幼儿识字软件测试自学,十大儿童识字APP排行,看看有你知道的吗?
  9. webtrends之ODBC源数据获取(二)——ACCESS访问篇
  10. 数据挖掘方面的论文指导(转)