如何通过代码而不是程序来截取手机屏幕的选定区域的截图?


当前回答

对于整页滚动截图

如果你想要捕捉一个完整的视图截图(其中包含一个滚动视图左右),那么在这个库中进行检查

https://github.com/peter1492/LongScreenshot

你所要做的就是导入Gradel,并创建一个bigscreen的对象

长截图=新BigScreenshot(这个,x, y);

当自动滚动屏幕视图组并在最后组装在一起时,将接收回调的屏幕截图位图。

get截图(Bitmap) {}

哪些可以保存到画廊或任何必要的用途,他们之后

其他回答

根据上面@JustinMorris和@NiravDangi的回答https://stackoverflow.com/a/8504958/2232148,我们必须把一个视图的背景和前景像这样组合起来:

public static Bitmap takeScreenshot(View view, Bitmap.Config quality) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), quality);
    Canvas canvas = new Canvas(bitmap);

    Drawable backgroundDrawable = view.getBackground();
    if (backgroundDrawable != null) {
        backgroundDrawable.draw(canvas);
    } else {
        canvas.drawColor(Color.WHITE);
    }
    view.draw(canvas);

    return bitmap;
}

质量参数取一个常数Bitmap。Config,通常是Bitmap.Config。RGB_565或Bitmap.Config.ARGB_8888。

如果你想捕捉一个视图的截图,使用View::drawToBitmap扩展函数:

val bitmap = myTargetView.drawToBitmap(/*Optional:*/ Bitmap.Config.ARGB_8888)

只需要确保使用-ktx版本的AndroidX核心库:

implementation("androidx.core:core-ktx:1.6.0")

我已经回答过一个类似的问题。

我的解决方案是:

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();
    }
}

图像保存在外部存储文件夹中。

作为参考,捕获屏幕(而不仅仅是应用程序活动)的一种方法是捕获帧缓冲区(device /dev/graphics/fb0)。要做到这一点,你必须拥有根权限,或者你的应用程序必须是一个具有签名权限的应用程序(“只有当请求应用程序与声明该权限的应用程序使用相同的证书进行签名时,系统才授予该权限”)-这是不太可能的,除非你编译了自己的ROM。

我测试过的几个设备上的每个framebuffer捕获都只包含一个截图。人们报告它包含更多,我猜这取决于框架/显示尺寸。

我尝试连续读取framebuffer,但它似乎返回了固定数量的读取字节。在我的例子中,这是(3 410 432)字节,这足以存储854*480 RGBA(3 279 360字节)的显示帧。是的,帧,二进制,从fb0输出是RGBA在我的设备。这很可能取决于不同的设备。这对你解码它很重要=)

在我的设备/dev/graphics/fb0权限是这样的,只有root和组图形的用户可以读取fb0。

图形是一个受限制的组,所以您可能只能使用su命令在根机中访问fb0。

Android应用程序的用户id (uid) = app_##,组id (guid) = app_##。

adb shell有uid = shell和guid = shell,它们拥有比app更多的权限。你可以在/system/permissions/platform.xml中查看这些权限

这意味着你将能够在没有根的adb shell中读取fb0,但如果没有根,你将无法在应用中读取它。

同样,在AndroidManifest.xml上给予READ_FRAME_BUFFER和/或ACCESS_SURFACE_FLINGER权限对常规应用没有任何作用,因为这些只对“签名”应用有效。

也检查这个关闭线程的更多细节。

这个方法不需要root权限,也不需要大量编码。


在adb shell上使用以下命令可以截屏。

input keyevent 120

这个命令不需要任何root权限,所以你也可以从android应用程序的java代码执行。

Process process;
process = Runtime.getRuntime().exec("input keyevent 120");

更多关于android中的keyevent代码,请参阅http://developer.android.com/reference/android/view/KeyEvent.html

这里我们用了。KEYCODE_SYSRQ,它的值是120,用于系统请求/打印屏幕键。


如CJBS所说,输出的图片将保存在/sdcard/Pictures/Screenshots