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 ...
随机推荐
- 随机四则运算 C语言
设计思想:出三十道一百以内数的随机四则运算题目,先随机两个一百以内的数字,再通过随机数确定四则运算算符,最后通过for循环输出三十道 源代码程序: #include <stdlib.h># ...
- 不会JS中的OOP,你也太菜了吧!(第一篇)
一.你必须知道的 1) 字面量 2) 原型 3) 原型链 4) 构造函数 5) 稳妥对象(没有公共属性,而且其方法也不引用this的对象.稳妥对象适合用在安全的环境中和防止数据被其它程序改变的时候) ...
- 深入探讨Java类加载机制
一.前言 毕业至今,已经三年光景,平时基本接触不到关于类加载器的技术(工作上),相信很多同行在开始工作后很长一段时间,对于类的加载机制都没有深入的了解过,之前偶然的机会接触了相关的知识,感觉挺有意思, ...
- 【转载】Mybatis多参数查询映射
转载地址:http://www.07net01.com/zhishi/402787.html 最近在做一个Mybatis的项目,由于是接触不久,虽然看了一下资料,但在实际开发中还是暴 露了很多问题,其 ...
- 8大排序算法图文讲解 分类: Brush Mode 2014-08-18 11:49 78人阅读 评论(0) 收藏
排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 常见的内部排序算法有:插入排序.希尔排序. ...
- 【bzoj1003】[ZJOI2006]物流运输
1003: [ZJOI2006]物流运输 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6331 Solved: 2610[Submit][Stat ...
- sprytabbedpanels.js库之在页面中插入Tabbed Panels
向页面加入sprytabbedpanels.js文件.<script src="SpryAssets/SpryTabbedPanels.js" type="text ...
- 理解Linux系统负荷[转]
一.查看系统负荷 在Linux系统中,我们一般使用uptime命令查看(w命令和top命令也行).(另外,它们在苹果公司的Mac电脑上也适用.) 二.一个类比 我们不妨把这个CPU想象成一座大桥, ...
- 网格导入设置 Import settings for Meshes
原地址:http://game.ceeger.com/Components/FBXImporter-Model.html The Import Settings for a model file wi ...
- Sqli-labs less 64
Less-64 此处的sql语句为 $sql="SELECT * FROM security.users WHERE id=(($id)) LIMIT 0,1"; 示例payloa ...