如何以编程方式在 Android 上截取屏幕截图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2661536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to programmatically take a screenshot on Android?
提问by korovaisdead
How can I take a screenshot of a selected area of phone-screen not by any program but from code?
如何不通过任何程序而是通过代码截取手机屏幕选定区域的屏幕截图?
采纳答案by taraloca
Here is the code that allowed my screenshot to be stored on an SD card and used later for whatever your needs are:
这是允许我的屏幕截图存储在 SD 卡上并稍后用于任何您需要的代码:
First, you need to add a proper permission to save the file:
首先,您需要添加适当的权限来保存文件:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
And this is the code (running in an Activity):
这是代码(在活动中运行):
private void takeScreenshot() {
Date now = new Date();
android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
try {
// image naming and path to include sd card appending name you choose for file
String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
// create bitmap screen capture
View v1 = getWindow().getDecorView().getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File imageFile = new File(mPath);
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
openScreenshot(imageFile);
} catch (Throwable e) {
// Several error may come out with file handling or DOM
e.printStackTrace();
}
}
And this is how you can open the recently generated image:
这是打开最近生成的图像的方法:
private void openScreenshot(File imageFile) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(imageFile);
intent.setDataAndType(uri, "image/*");
startActivity(intent);
}
If you want to use this on fragment view then use:
如果要在片段视图上使用它,请使用:
View v1 = getActivity().getWindow().getDecorView().getRootView();
instead of
代替
View v1 = getWindow().getDecorView().getRootView();
on takeScreenshot()function
上takeScreenshot()函数
Note:
注意:
This solution doesn't work if your dialog contains a surface view. For details please check the answer to the following question:
如果您的对话框包含表面视图,则此解决方案不起作用。有关详细信息,请查看以下问题的答案:
回答by JustinMorris
Call this method, passing in the outer most ViewGroup that you want a screen shot of:
调用此方法,传入您想要屏幕截图的最外层 ViewGroup:
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
回答by Viswanath Lekshmanan
Note: works only for rooted phone
注意:仅适用于有根电话
Programmatically, you can run adb shell /system/bin/screencap -p /sdcard/img.png
as below
以编程方式,您可以adb shell /system/bin/screencap -p /sdcard/img.png
按如下方式运行
Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
then read img.png
as Bitmap
and use as your wish.
然后读取img.png
的Bitmap
和你的愿望使用。
回答by GDR
EDIT: have mercy with the downvotes. It was true in 2010 when I answered the question.
编辑:怜悯否决票。我在 2010 年回答这个问题时确实如此。
All the programs which allow screenshots work only on rooted phones.
所有允许截图的程序只能在有 root 权限的手机上运行。
回答by Jeegar Patel
No root permissionor no big codingis required for this method.
此方法不需要 root 权限或不需要大量编码。
On adb shell using below command you can take screen shot.
在使用以下命令的 adb shell 上,您可以截取屏幕截图。
input keyevent 120
This command does not required any root permission so same you can perform from java code of android application also.
此命令不需要任何 root 权限,因此您也可以从 android 应用程序的 java 代码执行相同的操作。
Process process;
process = Runtime.getRuntime().exec("input keyevent 120");
More about keyevent code in android see http://developer.android.com/reference/android/view/KeyEvent.html
更多关于 android 中的 keyevent 代码见http://developer.android.com/reference/android/view/KeyEvent.html
Here we have used. KEYCODE_SYSRQits value is 120 and used for System Request / Print Screen key.
这里我们用到了。 KEYCODE_SYSRQ其值为 120,用于系统请求/打印屏幕键。
As CJBS said, The output picture will be saved in /sdcard/Pictures/Screenshots
正如CJBS所说,输出图片将保存在/sdcard/Pictures/Screenshots
回答by Crazy Coder
private void captureScreen() {
View v = getWindow().getDecorView().getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
try {
FileOutputStream fos = new FileOutputStream(new File(Environment
.getExternalStorageDirectory().toString(), "SCREEN"
+ System.currentTimeMillis() + ".png"));
bmp.compress(CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Add the permission in the manifest
在清单中添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
For Supporting Marshmallowor above versions, please add the below code in the activity onCreate method
支持Marshmallow或以上版本,请在活动的 onCreate 方法中添加以下代码
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
回答by xamar
Mualig answer is very good, but I had the same problem Ewoks describes, I'm not getting the background. So sometimes is good enough and sometimes I get black text over black background (depending on the theme).
Mualig 的回答非常好,但我遇到了 Ewoks 描述的同样问题,我没有了解背景。所以有时就足够了,有时我会在黑色背景上得到黑色文本(取决于主题)。
This solution is heavily based in Mualig code and the code I've found in Robotium. I'm discarding the use of drawing cache by calling directly to the draw method. Before that I'll try to get the background drawable from current activity to draw it first.
这个解决方案很大程度上基于 Mualig 代码和我在 Robotium 中找到的代码。我通过直接调用 draw 方法来放弃使用绘图缓存。在此之前,我将尝试从当前活动中获取可绘制的背景以先绘制它。
// Some constants
final static String SCREENSHOTS_LOCATIONS = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
// Get device dimmensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Get root view
View view = mCurrentUrlMask.getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_4444);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Activity activity = getCurrentActivity();
final Theme theme = activity.getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = activity.getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
// Save the screenshot to the file system
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS
+ System.currentTimeMillis() + ".jpg");
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos)) {
Log.d(LOGTAG, "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
回答by Rui Marques
As a reference, one way to capture the screen (and not just your app activity) is to capture the framebuffer(device /dev/graphics/fb0). To do this you must either have root privileges or your app must be an app with signature permissions("A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission") - which is very unlikely unless you compiled your own ROM.
作为参考,捕获屏幕(而不仅仅是您的应用程序活动)的一种方法是捕获帧缓冲区(设备 /dev/graphics/fb0)。为此,您必须具有 root 权限,或者您的应用程序必须是具有签名权限的应用程序(“只有当请求应用程序使用与声明权限的应用程序相同的证书签名时,系统才会授予该权限”) - 即除非您编译自己的 ROM,否则不太可能。
Each framebuffer capture, from a couple of devices I have tested, contained exactlyone screenshot. People have reported it to contain more, I guess it depends on the frame/display size.
每一帧缓冲区捕捉,从一对夫妇我已经测试设备,包含正好一个屏幕截图。人们报告它包含更多,我想这取决于框架/显示尺寸。
I tried to read the framebuffer continuously but it seems to return for a fixed amount of bytes read. In my case that is (3 410 432) bytes, which is enough to store a display frame of 854*480 RGBA (3 279 360 bytes). Yes, the frame, in binary, outputted from fb0 is RGBAin my device. This will most likely depend from device to device. This will be important for you to decode it =)
我试图连续读取帧缓冲区,但它似乎返回读取固定数量的字节。在我的情况下,这是 (3 410 432) 字节,足以存储 854*480 RGBA(3 279 360 字节)的显示帧。是的,从 fb0 输出的二进制帧在我的设备中是RGBA。这很可能取决于设备。这对您解码很重要 =)
In my device /dev/graphics/fb0permissions are so that only root and users from group graphics can read the fb0.
在我的设备中/dev/graphics/fb0权限是这样的,只有 root 和来自图形组的用户才能读取 fb0。
graphicsis a restricted group so you will probably only access fb0 with a rooted phone using su command.
graphics是一个受限制的组,因此您可能只能使用 su 命令通过 root 手机访问 fb0。
Android apps have the user id (uid) = app_##and group id (guid) = app_##.
Android 应用程序具有用户 ID (uid) = app_##和组 ID (guid) = app_##。
adb shellhas uid = shelland guid = shell, which has much more permissions than an app. You can actually check those permissions at /system/permissions/platform.xml
adb shell有uid = shell和guid = shell,它比应用程序拥有更多的权限。您实际上可以在 /system/permissions/platform.xml 中检查这些权限
This means you will be able to read fb0 in the adb shell without root but you will not read it within the app without root.
这意味着您将能够在没有 root 的情况下在 adb shell 中读取 fb0,但在没有 root 的情况下您将无法在应用程序中读取它。
Also, giving READ_FRAME_BUFFER and/or ACCESS_SURFACE_FLINGER permissions on AndroidManifest.xml will do nothing for a regular app because these will only work for 'signature' apps.
此外,在 AndroidManifest.xml 上授予 READ_FRAME_BUFFER 和/或 ACCESS_SURFACE_FLINGER 权限对常规应用程序没有任何作用,因为这些仅适用于“签名”应用程序。
Also check this closed threadfor more details.
另请查看此已关闭线程以获取更多详细信息。
回答by validcat
My solution is:
我的解决办法是:
public static Bitmap loadBitmapFromView(Context context, View v) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
v.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap returnedBitmap = Bitmap.createBitmap(v.getMeasuredWidth(),
v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
v.draw(c);
return returnedBitmap;
}
and
和
public void takeScreen() {
Bitmap bitmap = ImageUtils.loadBitmapFromView(this, view); //get Bitmap from the view
String mPath = Environment.getExternalStorageDirectory() + File.separator + "screen_" + System.currentTimeMillis() + ".jpeg";
File imageFile = new File(mPath);
OutputStream fout = null;
try {
fout = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
fout.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fout.close();
}
}
Images are saved in the external storage folder.
图像保存在外部存储文件夹中。
回答by Kuba
You can try the following library: http://code.google.com/p/android-screenshot-library/Android Screenshot Library (ASL) enables to programmatically capture screenshots from Android devices without requirement of having root access privileges. Instead, ASL utilizes a native service running in the background, started via the Android Debug Bridge (ADB) once per device boot.
您可以尝试使用以下库:http: //code.google.com/p/android-screenshot-library/Android 屏幕截图库 (ASL) 能够以编程方式从 Android 设备捕获屏幕截图,而无需具有 root 访问权限。相反,ASL 使用在后台运行的本机服务,每次设备启动时通过 Android 调试桥 (ADB) 启动一次。