原文地址:http://www.codeweblog.com/android%E6%88%AA%E5%B1%8F%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E6%B3%95/
android截屏的几种方法
1. Surface.screenshot方法
try{
Display display = getWindowManager().getDefaultDisplay();
Method mth = Surface.class.getDeclaredMethod("screenshot", int.class, int.class);
Bitmap bmp = (Bitmap)mth.invoke(null, display.getWidth(),display.getHeight());
OutputStream out = MainActivity.this.openFileOutput("screen.png", MODE_WORLD_READABLE);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
Log.i("zxp","capture succeed");
}catch(Exception e){
Log.e("zxp","unable capture screen: ",e);
}
即通过反射调用Surface的隐藏方法public static native Bitmap screenshot(int width, int height);
。此方法需要android.permission.READ_FRAME_BUFFER
权限,而这个权限只能授予系统应用。所以需要源码编译或使用plantform密钥签名。因为android项目是开源的,所以可以使用aosp项目的密钥。
另外需要在AndroidManifext.xml中的manifest标签中添加android:sharedUserId="android.uid.system"
局限:只能在虚拟机或其他使用android源码中密钥编译的系统中使用。
在安卓4.0 到 4.2时,com.android.view.Surface有个隐藏的API: public static Bitmap screenshot(int width, int height) 可以用于截屏,Surface这个class本身是没有hide标志的,只是screenshot方法有hide。添加READ_FRAME_BUFFER权限,在源码环境下用platform签名编译,调用Surface.screenshot(width, height)能正确运行并截屏返回Bitmap。
安卓4.3及以后screenshot方法被修改到了com.android.view.SurfaceControl中,SurfaceControl这个class是hide的。使用和上述4.2中同样的操作,在安卓4.4系统中编译,调用SurfaceControl.screenshot(width, height),
2. 使用shell命令screencap,screenshot
screencap与screenshot用法
usage: screencap [-hp] [-d display-id] [FILENAME]
-h: this message
-p: save the file as a png.
-d: specify the display id to capture, default 0.
If FILENAME ends with .png it will be saved as a png.
If FILENAME is not given, the results will be printed to stdout.
---------------------------------------------------------------
usage: screenshot [-s soundfile] filename.png
-s: play a sound effect to signal success
-i: autoincrement to avoid overwriting filename.png
screencap与screenshot都可以截屏并保存为文件。但screencap可以将截取的图片直接打印到输出流。对于一些其他操作而不需要保存到文件时可以使用screencap。
局限:需要root权限。
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
//转为灰色图片或其他操作
Bitmap bmp = convert2Grey(captureScreen());
//保存到文件
OutputStream out = openFileOutput("gray.png",
Context.MODE_WORLD_READABLE);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
Log.i("zxp", "capture succeed");
} catch (Exception e) {
Log.e("zxp", "unable capture screen: ", e);
}
}
});
public Bitmap captureScreen() throws Exception {
Process pro = Runtime.getRuntime().exec("su -c screencap -p");
InputStream in = pro.getInputStream();
Bitmap bmp = BitmapFactory.decodeStream(in);
in.close();
pro.destroy();
return bmp;
}
public Bitmap convert2Grey(Bitmap img) {
int width = img.getWidth(); // 获取位图的宽
int height = img.getHeight(); // 获取位图的高
int[] pixels = new int[width * height]; // 通过位图的大小创建像素点数组
img.getPixels(pixels, 0, width, 0, 0, width, height);
int alpha = 0xFF << 24;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int grey = pixels[width * i + j];
int red = ((grey & 0x00FF0000) >> 16);
int green = ((grey & 0x0000FF00) >> 8);
int blue = (grey & 0x000000FF);
grey = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);
grey = alpha | (grey << 16) | (grey << 8) | grey;
pixels[width * i + j] = grey;
}
}
Bitmap result = Bitmap.createBitmap(width, height, Config.RGB_565);
result.setPixels(pixels, 0, width, 0, 0, width, height);
return result;
}
3.View.getDrawingCache()
这个方法没有其他限制,但它只能取得调用者的图像。
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
//因为调用者是被点击的button,所以只能取得该Button的图像
v.setDrawingCacheEnabled(true);
Bitmap bmp = v.getDrawingCache();
OutputStream out = openFileOutput("button.png",
Context.MODE_WORLD_READABLE);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
Log.i("zxp", "capture succeed");
} catch (Exception e) {
Log.e("zxp", "unable capture screen: ", e);
}
}
});
上述代码的调用结果如下:
但可以调用顶级view取得整个activity的图像
public Bitmap getTopView(){
View view = getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
return view.getDrawingCache();
}
局限:该方法只能取得调用者view的图像,也就是说这不是实际意义上的“截屏”.