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


当前回答

如果你想捕捉一个视图或布局,比如RelativeLayout或LinearLayout等。

只需使用代码:

LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);

现在你可以保存这个位图在设备存储:

FileOutputStream outStream = null;
File f=new File(Environment.getExternalStorageDirectory()+"/Screen Shots/");
f.mkdir();
String extStorageDirectory = f.toString();
File file = new File(extStorageDirectory, "my new screen shot");
pathOfImage = file.getAbsolutePath();
try {
    outStream = new FileOutputStream(file);
    bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
    Toast.makeText(getApplicationContext(), "Saved at "+f.getAbsolutePath(), Toast.LENGTH_LONG).show();
    addImageGallery(file);
    //mail.setEnabled(true);
    flag=true;
} catch (FileNotFoundException e) {e.printStackTrace();}
try {
    outStream.flush();
    outStream.close();
} catch (IOException e) {e.printStackTrace();}

其他回答

public class ScreenShotActivity extends Activity{

private RelativeLayout relativeLayout;
private Bitmap myBitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    relativeLayout = (RelativeLayout)findViewById(R.id.relative1);
    relativeLayout.post(new Runnable() {
        public void run() {

            //take screenshot
            myBitmap = captureScreen(relativeLayout);

            Toast.makeText(getApplicationContext(), "Screenshot captured..!", Toast.LENGTH_LONG).show();

            try {
                if(myBitmap!=null){
                    //save image to SD card
                    saveImage(myBitmap);
                }
                Toast.makeText(getApplicationContext(), "Screenshot saved..!", Toast.LENGTH_LONG).show();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    });

}

public static Bitmap captureScreen(View v) {

    Bitmap screenshot = null;
    try {

        if(v!=null) {

            screenshot = Bitmap.createBitmap(v.getMeasuredWidth(),v.getMeasuredHeight(), Config.ARGB_8888);
            Canvas canvas = new Canvas(screenshot);
            v.draw(canvas);
        }

    }catch (Exception e){
        Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
    }

    return screenshot;
}

public static void saveImage(Bitmap bitmap) throws IOException{

    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 40, bytes);
    File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.png");
    f.createNewFile();
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
    fo.close();
}

}

添加权限

< uses-permission android: name = " android.permission.WRITE_EXTERNAL_STORAGE " / >

作为参考,捕获屏幕(而不仅仅是应用程序活动)的一种方法是捕获帧缓冲区(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权限对常规应用没有任何作用,因为这些只对“签名”应用有效。

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

科特林

    private fun screenShot() {
          try {
            val mPath: String = this.getExternalFilesDir(null).getAbsolutePath()
              .toString() + "/temp" + ".png" 
            // create bitmap screenshot
            val v1: View = getWindow().getDecorView().getRootView()
            v1.isDrawingCacheEnabled = true
            val bitmap = Bitmap.createBitmap(v1.drawingCache)
            v1.isDrawingCacheEnabled = false
            val imageFile = File(mPath)
            val outputStream = FileOutputStream(imageFile)
            val quality = 100
            bitmap.compress(Bitmap.CompressFormat.PNG, quality, outputStream)
            outputStream.flush()
            outputStream.close()
        
            //or you can share to test the method fast
            val uriPath =
              FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile)
            val intent = Intent(Intent.ACTION_SEND)
            intent.type = "image/*"
            intent.clipData = ClipData.newRawUri("", uriPath)
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            intent.putExtra(Intent.EXTRA_STREAM, uriPath)
            startActivity(Intent.createChooser(intent, "Sharing to..."))
          } catch (e: Throwable) {
            e.printStackTrace()
          }
        }

Java

  private void screenShot() {
    try {
      String mPath = this.getExternalFilesDir(null).getAbsolutePath().toString() + "/temp" + ".png";
      // create bitmap screenshot
      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.PNG, quality, outputStream);
      outputStream.flush();
      outputStream.close();

      //or you can share to test the method fast

      Uri uriPath = FileProvider.getUriForFile(this, getPackageName() + ".sharing.provider", imageFile);
      Intent intent = new Intent(Intent.ACTION_SEND);
      intent.setType("image/*");
      intent.setClipData(ClipData.newRawUri("", uriPath));
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
      intent.putExtra(Intent.EXTRA_STREAM, uriPath);
      startActivity(Intent.createChooser(intent, "Sharing to..."));

    } catch (Throwable e) {
      e.printStackTrace();
    }
  }

您可以尝试以下库: http://code.google.com/p/android-screenshot-library/ Android截图库(ASL)允许以编程方式从Android设备捕获屏幕截图,而不需要具有root访问权限。相反,ASL利用了在后台运行的本地服务,每次设备启动时通过Android调试桥(ADB)启动。

如果你想从片段中截取截图,请遵循以下步骤:

Override onCreateView(): @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_one, container, false); mView = view; } Logic for taking screenshot: button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { View view = mView.findViewById(R.id.scrollView1); shareScreenShotM(view, (NestedScrollView) view); } method shareScreenShotM)(): public void shareScreenShotM(View view, NestedScrollView scrollView){ bm = takeScreenShot(view,scrollView); //method to take screenshot File file = savePic(bm); // method to save screenshot in phone. } method takeScreenShot(): public Bitmap takeScreenShot(View u, NestedScrollView z){ u.setDrawingCacheEnabled(true); int totalHeight = z.getChildAt(0).getHeight(); int totalWidth = z.getChildAt(0).getWidth(); Log.d("yoheight",""+ totalHeight); Log.d("yowidth",""+ totalWidth); u.layout(0, 0, totalWidth, totalHeight); u.buildDrawingCache(); Bitmap b = Bitmap.createBitmap(u.getDrawingCache()); u.setDrawingCacheEnabled(false); u.destroyDrawingCache(); return b; } method savePic(): public static File savePic(Bitmap bm){ ByteArrayOutputStream bytes = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.JPEG, 100, bytes); File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + "/Foldername"); if (!sdCardDirectory.exists()) { sdCardDirectory.mkdirs(); } // File file = new File(dir, fileName); try { file = new File(sdCardDirectory, Calendar.getInstance() .getTimeInMillis() + ".jpg"); file.createNewFile(); new FileOutputStream(file).write(bytes.toByteArray()); Log.d("Fabsolute", "File Saved::--->" + file.getAbsolutePath()); Log.d("Sabsolute", "File Saved::--->" + sdCardDirectory.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } return file; }

对于activity,您可以简单地使用View v1 = getWindow().getDecorView().getRootView();而不是mView