如何捕获 android 设备屏幕内容并使用快照数据制作图像文件?我应该使用哪个 API 或在哪里可以找到相关资源?
顺便说一句:不是相机快照,而是设备屏幕
如何捕获 android 设备屏幕内容并使用快照数据制作图像文件?我应该使用哪个 API 或在哪里可以找到相关资源?
顺便说一句:不是相机快照,而是设备屏幕
使用以下代码:
Bitmap bitmap;
View v1 = MyView.getRootView();
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
这MyView
是View
我们需要在屏幕中包含的内容。您也可以DrawingCache
通过任何View
这种方式获取(不带getRootView()
)。
还有另一种方法..
如果我们有ScrollView
作为根视图,那么最好使用以下代码,
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
FrameLayout root = (FrameLayout) inflater.inflate(R.layout.activity_main, null); // activity_main is UI(xml) file we used in our Activity class. FrameLayout is root view of my UI(xml) file.
root.setDrawingCacheEnabled(true);
Bitmap bitmap = getBitmapFromView(this.getWindow().findViewById(R.id.frameLayout)); // here give id of our root layout (here its my FrameLayout's id)
root.setDrawingCacheEnabled(false);
这是getBitmapFromView()
方法
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
else
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
它将显示整个屏幕,包括隐藏在您的ScrollView
UPDATED AS ON 20-04-2016
中的内容
还有另一种更好的截屏方法。
在这里,我截取了WebView
.
WebView w = new WebView(this);
w.setWebViewClient(new WebViewClient()
{
public void onPageFinished(final WebView webView, String url) {
new Handler().postDelayed(new Runnable(){
@Override
public void run() {
webView.measure(View.MeasureSpec.makeMeasureSpec(
View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
webView.layout(0, 0, webView.getMeasuredWidth(),
webView.getMeasuredHeight());
webView.setDrawingCacheEnabled(true);
webView.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(),
webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
int height = bitmap.getHeight();
canvas.drawBitmap(bitmap, 0, height, paint);
webView.draw(canvas);
if (bitmap != null) {
try {
String filePath = Environment.getExternalStorageDirectory()
.toString();
OutputStream out = null;
File file = new File(filePath, "/webviewScreenShot.png");
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 50, out);
out.flush();
out.close();
bitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, 1000);
}
});
希望这可以帮助..!
AFAIK,目前捕获android屏幕截图的所有方法都使用/dev/graphics/fb0帧缓冲区。这包括ddms。它确实需要 root 才能从此流中读取。ddms 使用 adbd 请求信息,因此不需要 root,因为 adb 具有从 /dev/graphics/fb0 请求数据所需的权限。
帧缓冲区包含 2+“帧”的 RGB565 图像。如果您能够读取数据,则必须知道屏幕分辨率才能知道获取图像需要多少字节。每个像素为 2 个字节,因此如果屏幕分辨率为 480x800,则您必须为图像读取 768,000 字节,因为 480x800 RGB565 图像有 384,000 个像素。
screencap
对于较新的 Android 平台,可以在没有 root 权限的情况下执行系统实用程序/system/bin
来获取屏幕截图。你可以尝试/system/bin/screencap -h
看看如何在 adb 或任何 shell 下使用它。
顺便说一句,我认为这种方法只适用于单个快照。如果我们要捕获多个帧进行屏幕播放,它会太慢。我不知道是否有任何其他方法可以更快地截屏。
【基于Android源码:】
在 C++ 端,SurfaceFlinger 实现了 captureScreen API。这暴露在 binder IPC 接口上,每次返回一个新的 ashmem 区域,其中包含来自屏幕的原始像素。实际的屏幕截图是通过 OpenGL 截取的。
对于系统 C++ 客户端,接口通过 ScreenshotClient 类公开,在<surfaceflinger_client/SurfaceComposerClient.h>
Android < 4.1 中定义;适用于 Android > 4.1 使用<gui/SurfaceComposerClient.h>
在 JB 之前,要在 C++ 程序中截屏,这就足够了:
ScreenshotClient ssc;
ssc.update();
使用 JB 和多显示器,它会变得稍微复杂一些:
ssc.update(
android::SurfaceComposerClient::getBuiltInDisplay(
android::ISurfaceComposer::eDisplayIdMain));
然后你可以访问它:
do_something_with_raw_bits(ssc.getPixels(), ssc.getSize(), ...);
使用 Android 源代码,您可以编译自己的共享库来访问该 API,然后通过 JNI 将其公开给 Java。要为您的应用创建屏幕截图,该应用必须具有READ_FRAME_BUFFER
权限。但即便如此,显然您只能从系统应用程序创建屏幕截图,即使用与系统相同的密钥签名的应用程序。(这部分我还是不太明白,因为我对Android Permissions系统还不够熟悉。)
这是一段代码,适用于 JB 4.1 / 4.2:
#include <utils/RefBase.h>
#include <binder/IBinder.h>
#include <binder/MemoryHeapBase.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
static void do_save(const char *filename, const void *buf, size_t size) {
int out = open(filename, O_RDWR|O_CREAT, 0666);
int len = write(out, buf, size);
printf("Wrote %d bytes to out.\n", len);
close(out);
}
int main(int ac, char **av) {
android::ScreenshotClient ssc;
const void *pixels;
size_t size;
int buffer_index;
if(ssc.update(
android::SurfaceComposerClient::getBuiltInDisplay(
android::ISurfaceComposer::eDisplayIdMain)) != NO_ERROR ){
printf("Captured: w=%d, h=%d, format=%d\n");
ssc.getWidth(), ssc.getHeight(), ssc.getFormat());
size = ssc.getSize();
do_save(av[1], pixels, size);
}
else
printf(" screen shot client Captured Failed");
return 0;
}
您可以尝试以下库:Android 屏幕截图库 (ASL)能够以编程方式从 Android 设备捕获屏幕截图,而无需具有 root 访问权限。相反,ASL 使用在后台运行的本机服务,每次设备启动时通过 Android 调试桥 (ADB) 启动一次。
根据此链接,可以使用android sdk的工具目录中的ddms进行屏幕截图。
要在应用程序中(而不是在开发期间)执行此操作,也有应用程序可以执行此操作。但正如@zed_0xff 指出的那样,它肯定需要root。
帧缓冲区似乎是要走的路,它并不总是像 Ryan Conrad 提到的那样包含 2+ 帧。就我而言,它只包含一个。我想这取决于框架/显示尺寸。
我试图连续读取帧缓冲区,但它似乎返回了固定数量的读取字节。在我的例子中是 (3 410 432) 字节,这足以存储 854*480 RGBA(3 279 360 字节)的显示帧。是的,从 fb0 输出的二进制帧在我的设备中是 RGBA。这很可能取决于不同的设备。这对你解码很重要=)
在我的设备 /dev/graphics/fb0 权限中,只有 root和图形组中的用户才能读取fb0。graphics是一个受限组,因此您可能只能使用 su 命令通过 root 手机访问 fb0。
Android 应用具有用户 ID (uid) app_##和组 ID (guid) app_##。
adb shell 有uid shell和guid shell,它们比应用程序拥有更多的权限。您实际上可以在/system/permissions/platform.xml中检查这些权限
这意味着您将能够在没有 root 的情况下在 adb shell 中读取 fb0,但在没有 root 的情况下您将无法在应用程序中读取它。
此外,在 AndroidManifest.xml 上授予 READ_FRAME_BUFFER 和/或 ACCESS_SURFACE_FLINGER 权限对于常规应用程序没有任何作用,因为这些仅适用于“签名”应用程序。
如果您想在 Android 应用程序 AFAIK 中从 Java 代码进行屏幕截图,您必须具有 Root 权限。