Android应用截图和SurfaceView截图问题总结
最近在做android截图应用的过程遇到很多问题,接触了好些截图方法,但是还是不能实现SufaceView截图功能。今天就把我尝试过的方法总结下,希望把我惨痛的经历写出来后能够帮助到要做此功能的朋友少走弯路,或者是给一些思路吧。如果哪位大侠能够做到SurfaceView截图,还请分享下思路。
一、无SurfaceView情况下的截图功能实现
public static Bitmap takeScreenShot(Activity act) {
if (act == null || act.isFinishing()) {
Log.d(TAG, "act参数为空.");
return null;
} // 获取当前视图的view
View scrView = act.getWindow().getDecorView();
scrView.setDrawingCacheEnabled(true);
scrView.buildDrawingCache(true); // 获取状态栏高度
Rect statuBarRect = new Rect();
scrView.getWindowVisibleDisplayFrame(statuBarRect);
int statusBarHeight = statuBarRect.top;
int width = act.getWindowManager().getDefaultDisplay().getWidth();
int height = act.getWindowManager().getDefaultDisplay().getHeight(); Bitmap scrBmp = null;
try {
// 去掉标题栏的截图
scrBmp = Bitmap.createBitmap( scrView.getDrawingCache(), , statusBarHeight,
width, height - statusBarHeight);
} catch (IllegalArgumentException e) {
Log.d("", "#### 旋转屏幕导致去掉状态栏失败");
}
scrView.setDrawingCacheEnabled(false);
scrView.destroyDrawingCache();
return scrBmp;
}
这种情况只能够截取普通应用的截图,当应用含有SurfaceView时, SurfaceView区域为黑色,具体什么原因,请移步:http://blog.csdn.net/luoshengyang/article/details/8661317。
二、含有SurfaceView的截图实现
2.1 系统root的情况下的实现代码
private static final String DEVICE_NAME = "/dev/graphics/fb0";
@SuppressWarnings("deprecation")
public static Bitmap acquireScreenshot(Context context) {
WindowManager mWinManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
Display display = mWinManager.getDefaultDisplay();
display.getMetrics(metrics);
// 屏幕高
int height = metrics.heightPixels;
// 屏幕的宽
int width = metrics.widthPixels; int pixelformat = display.getPixelFormat();
PixelFormat localPixelFormat1 = new PixelFormat();
PixelFormat.getPixelFormatInfo(pixelformat, localPixelFormat1);
// 位深
int deepth = localPixelFormat1.bytesPerPixel; byte[] arrayOfByte = new byte[height * width * deepth];
try {
// 读取设备缓存,获取屏幕图像流
InputStream localInputStream = readAsRoot();
DataInputStream localDataInputStream = new DataInputStream(
localInputStream);
localDataInputStream.readFully(arrayOfByte);
localInputStream.close(); int[] tmpColor = new int[width * height];
int r, g, b;
for (int j = ; j < width * height * deepth; j += deepth) {
b = arrayOfByte[j] & 0xff;
g = arrayOfByte[j + ] & 0xff;
r = arrayOfByte[j + ] & 0xff;
tmpColor[j / deepth] = (r << ) | (g << ) | b | (0xff000000);
}
// 构建bitmap
Bitmap scrBitmap = Bitmap.createBitmap(tmpColor, width, height,
Bitmap.Config.ARGB_8888);
return scrBitmap; } catch (Exception e) {
Log.d(TAG, "#### 读取屏幕截图失败");
e.printStackTrace();
}
return null; } /**
* @Title: readAsRoot
* @Description: 以root权限读取屏幕截图
* @throws Exception
* @throws
*/
public static InputStream readAsRoot() throws Exception {
File deviceFile = new File(DEVICE_NAME);
Process localProcess = Runtime.getRuntime().exec("su");
String str = "cat " + deviceFile.getAbsolutePath() + "\n";
localProcess.getOutputStream().write(str.getBytes());
return localProcess.getInputStream();
}
系统root的时候,可以直接读取frame buffer, 因此即使含有SurfaceView也能够读取整个窗口的图像。
2.2 使用SurfaceView和MediaPlayer来播放视频的情况,这里只获取SurfaceView的图像
/**
* @Title: getVideoFrame
* @Description: 获取视频某帧的图像,但得到的图像并不一定是指定position的图像。
* @param path 视频的本地路径
* @param position 视频流播放的position
* @return Bitmap 返回的视频图像
* @throws
*/
@SuppressLint("NewApi")
public static Bitmap getVideoFrame(String path, MediaPlayer mediaPlayer) { Bitmap bmp = null;
// android 9及其以上版本可以使用该方法
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(path);
// 这一句是必须的
String timeString =
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
// 获取总长度,这一句也是必须的
long titalTime = Long.parseLong(timeString) * ; long videoPosition = ;
try {
mediaPlayer.setDataSource(path);
if (path.startsWith("http")) {
mediaPlayer.prepareAsync();
} else {
mediaPlayer.prepare();
}
int duration = mediaPlayer.getDuration();
// 通过这个计算出想截取的画面所在的时间
videoPosition = titalTime * position / duration;
} catch (IOException e) {
e.printStackTrace();
}
if (videoPosition > ) {
bmp = retriever.getFrameAtTime(videoPosition,
MediaMetadataRetriever.OPTION_CLOSEST);
}
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
} catch (RuntimeException ex) {
ex.printStackTrace();
} finally {
try {
retriever.release();
} catch (RuntimeException ex) {
}
}
return bmp;
}
以上代码单纯的获取 SurfaceView上的图像,其他控件的图像并没有获取。其原理是读取本地文件某一position的图像,而不是截图。
2.3 没有root,又有SurfaceView,还想截图 ?
这个方法我并没有成功,也不知道是否真的能够实现,这里给出相关资料,希望有需要的朋友能够得到帮助,如果能够实现,还请留个言指教一下,不甚感激。
《Pro android c++ with NDK》的第十二张的Using Graphic API中的Using Native Window API.
结尾:
在经过很多探索后,请教了国内《深入Android系统》系列作者邓凡平,他给出的答案为:
我知道你说的。我也做过截屏的软件,但是视频图像截不了。
就我之前的研究来看,视频数据解码后直接由解码芯片推到屏幕上了,根本就不会
通过surfaceflinger来混屏,在高通芯片上就是如此。
你想想吧,windows和Linux的截屏软件都无法截取视频播放的图像,正是这个原因。 不过有些芯片平台也许会将视频数据通过surfaceflinger来混屏,我个人觉得这种情况比较少。
Br
邓凡平
总之,这条路似乎很难走通,希望有有需求的朋友少走弯路吧。
Android应用截图和SurfaceView截图问题总结的更多相关文章
- Android之View和SurfaceView
Android之View和SurfaceView Android游戏当中主要的除了控制类外就是显示类View.SurfaceView是从View基类中派生出来的显示类.android游戏开发中常用的三 ...
- Android 学习笔记之SurfaceView的使用+如何实现视频播放...
学习内容: 1.掌握Surface的使用... 2.Android中如何实现视频播放... 1.SurfaceView类的使用 在Android中,一般播放音频时我们可以去使用Android提供的 ...
- C#区域截图——调用API截图
原文:C#区域截图——调用API截图 前言:截图对于一个C++开发者来说无非是小菜一碟,也有朋友使用C#的 Graphics.CopyFromScreen 方法屏幕操作,作为一名整天想着用 C++ 开 ...
- 【转】Android Fragment中使用SurfaceView切换时闪一下黑屏的解决办法
重构了下之前自己的一个新闻客户端,全部使用了Fragment来进行页面切换,只有一个入口Activity作为程序的启动Activity,其中有一个界面需要调用摄像头识别二维码, 于是就会用到Surfa ...
- Android之WebView网页滚动截图
WebView 网页滚动截屏,可对整个网页进行截屏而不是仅当前屏幕哦! 注意若Web页面存在position:fixed; 的话得在调用前设置为 position:absolute; 哦,否则会出现很 ...
- android view 转Bitmap 生成截图
文章链接:https://mp.weixin.qq.com/s/FQmYfT-KYiDbp-0HzK_Hpw 项目中经常会用到分享的功能,有分享链接也有分享图片,其中分享图片有的需要移动端对屏幕内容进 ...
- 玩转Android Camera开发(一):Surfaceview预览Camera,基础拍照功能完整demo
杂家前文是在2012年的除夕之夜仓促完成,后来很多人指出了一些问题,琐事缠身一直没有进行升级.后来随着我自己的使用,越来越发现不出个升级版的demo是不行了.有时候就连我自己用这个demo测一些性能. ...
- android 使用两个surfaceview 在摄像机画面上绘图
转载自http://blog.csdn.net/jesse__zhong/article/details/24934083 使用双surface,将第一个设置为透明背景,在摄像机上绘制图像,纠结搞了一 ...
- Android Button悬浮在SurfaceView上
实现Button悬浮于与SurfaceView之上实现 注意:你实现的SurfaceView和android中的Button,EditView是同级的,不能把一个包含在另一个里面 1.创建自己的Sur ...
随机推荐
- Android -- Home按键
游戏中常常需要监听android HOME键,当HOME键下压时,往往需要做一些状态保存,音效停止等操作,那么如何做,才能监听到HOME键呢?我们知道HOME是系统键,app中无法通过onKey这些函 ...
- U盘安装 Windows XP 原版 ISO 的几点心得
虽然我一直致力于推动最新操作系统的部署,劝说周围朋友尽快淘汰 Windows XP,但还是难免有一些老电脑.老朋友的电脑,坚持要使用 XP 系统. 这里有几点使用U盘安装 Windows XP 原版 ...
- l2tp vpn客户端
1. 添加PPA sudo apt-add-repository ppa:seriy-pr/network-manager-l2tp 2. 刷新软件包缓存 sudo apt-get upd ...
- 怎么用PHP发送HTTP请求(转载)
本文转自:http://blog.snsgou.com/blog/161.html file_get_contents版本: /** * 发送post请求 * @param string $url ...
- springmvc返回jsp源代码解决办法
url-pattern问题 spring用到forward("/WEB-INF/jsp/*.jsp")而forward当然是又要经过web.xml的映射的,然后,在URL匹配时, ...
- 设计模式 --深入理解javascript
/* 一.单例模式 */ var Universe; (function () { var instance; Universe = function Universe() { if (instanc ...
- UIlabel 显示模糊
问题: 今天遇到连续两个label一个显示的比较清楚,比较锐利,而另一个对比下有点模糊. 原因: 在使用UILabel等继承于UIView的控件时,如果frame的rect不是整数的情况下,就会显示起 ...
- Linux网络编程实例解析
**************************************************************************************************** ...
- SQL Server 2008中新增的 1.变更数据捕获(CDC) 和 2.更改跟踪
概述 1.变更数据捕获(CDC) 每一次的数据操作都会记录下来 2.更改跟踪 只会记录最新一条记录 以上两种的区别: http://blog.csdn.n ...
- 10 个让人惊讶的 jQuery 插件
说是让人惊讶,你可能会觉得我们没见过世面,但这里提及的一些 jQuery 的插件的确平时比较少见,用的人应该更少. Grid portfolio 使用竖排方式显示条目信息,现在很流行的的内容布局方式. ...