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 ...
随机推荐
- JavaScript深复制
转载:http://blog.csdn.net/wanmingtom/article/details/7988284 这原本是StackOverFlow里的一个提问,看到答案后受益良多,于是翻译一下下 ...
- 测试web数据库的分布式事务atomikos 的三种数据源 SimpleDataSourceBean,AtomikosDataSourceBean,AtomikosNonXADataSourceBean
这2天学习了atomikos事务控制框架,其中看到有3种数据源,分别是,SimpleDataSourceBean,AtomikosDataSourceBean,AtomikosNonXADataSou ...
- 重装系统必做之——更换Windows系统的默认临时文件的存储目录
作为一名计算机爱好者,重装电脑是家常便饭,但是重装电脑的目的无非就是: 1.操作系统更新换代: 2.系统速度太慢: 或者更多.... 我们大多数目的都是上述中第2点,有时候是否仅仅重装系统而忽略了一些 ...
- python 字典列表排序operator.itemgetter()
举例: import operator x = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}] sorted_x = sorted(x, ...
- bzoj 1028 暴力枚举判断
昨天梦到这道题了,所以一定要A掉(其实梦到了3道,有两道记不清了) 暴力枚举等的是哪张牌,将是哪张牌,然后贪心的判断就行了. 对于一个状态判断是否为胡牌,1-n扫一遍,然后对于每个牌,先mod 3, ...
- Leetcode#147 Insertion Sort List
原题地址 心得:有关链表的题目,多用中间变量,代码写得清晰一点,适当注释 代码: ListNode *insertionSortList(ListNode *head) { if (!head) re ...
- Leetcode#90 Subsets II
原题地址 跟Subsets(参见这篇文章)类似. 但因为有重复元素,所以要考虑去重问题. 什么情况下会出现重复呢?比如S = {5, 5, 5},如果要选1个5,一共有C(3,1)=3种选法,即100 ...
- xcodebuild和xcrun实现自动打包iOS应用程序
随着苹果手持设备用户的不断增加,ios应用也增长迅速,同时随着iphone被越狱越来越多的app 的渠道也不断增多,为各个渠道打包成了一件费时费力的工作,本文提供一种比较智能的打包方式来减少其带来的各 ...
- 深入理解python之self
首先明确的是self只有在类的方法中才会有,独立的函数或方法是不必带有self的.self在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数. self名称不是必须的,在python中self ...
- .NET设计模式(17):命令模式(Command Pattern)(转)
概述 在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”.但在某些场合,比如要对行为进行“记录.撤销/重做.事务”等处理,这种无法抵御变化的紧耦合是不合适的.在这种情况下,如何将“行为 ...