Làm thế nào để lập trình chụp ảnh màn hình trên Android?


495

Làm cách nào tôi có thể chụp ảnh màn hình của một khu vực được chọn trên màn hình điện thoại không phải bởi bất kỳ chương trình nào mà từ mã?


4
Không phải từ trình giả lập. Tôi cần phải tạo ảnh chụp màn hình của một phần chương trình của mình và thực hiện smth với nó trong cùng một chương trình.
korova thẩm quyền

1
Một tài liệu tham khảo hay khác: stackoverflow.com/a/10296881/439171
Italo Borssatto

Câu trả lời:


448

Đây là mã cho phép ảnh chụp màn hình của tôi được lưu trên thẻ SD và được sử dụng sau này cho bất kỳ nhu cầu nào của bạn:

Trước tiên, bạn cần thêm một quyền thích hợp để lưu tệp:

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

Và đây là mã (chạy trong một Hoạt động):

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

Và đây là cách bạn có thể mở hình ảnh được tạo gần đây:

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

Nếu bạn muốn sử dụng điều này trên chế độ xem phân đoạn thì hãy sử dụng:

View v1 = getActivity().getWindow().getDecorView().getRootView();

thay vì

View v1 = getWindow().getDecorView().getRootView();

trên takeScreenshot () chức năng

Lưu ý :

Giải pháp này không hoạt động nếu hộp thoại của bạn chứa chế độ xem bề mặt. Để biết chi tiết xin vui lòng kiểm tra câu trả lời cho câu hỏi sau đây:

Android Chụp ảnh màn hình của Surface View cho thấy màn hình đen


23
Xin chào, bạn có thể mô tả mCienUrlMask là gì không? Tôi đã thử mã này nhưng nó luôn mang lại cho tôi NullPulumException tại Bitmap.createBitmap (v1.getDrawingCache ()), có ai có thể nói tôi đang làm gì sai không? Bất kỳ trợ giúp được đánh giá cao. Cảm ơn.
Mitesh Sardhara

4
@MiteshSardhara mCurrentUrlMaskphải là một Viewlớp duy nhất trong API Android có getRootView()phương thức. Có lẽ là một cái nhìn trong UI.
gipi

6
Bạn có thể vui lòng cho tôi biết, mCienUrlMask là gì không?
Jayeshkumar Sojitra

37
Ngay lập tức View v1 = mCurrentUrlMask.getRootView();tôi đã sử dụng View v1 = getWindow().getDecorView().getRootView();và nó hoạt động cho tôi.
enadun

9
Câu trả lời này chỉ có một ảnh chụp màn hình của ứng dụng - không phải là "màn hình điện thoại" như được hỏi trong câu hỏi - hoặc tôi đang làm gì đó sai.
AlikElzin-kilaka

126

Gọi phương thức này, chuyển qua hầu hết Viewgroup bên ngoài mà bạn muốn có ảnh chụp màn hình:

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

9
Đây có vẻ là mã sạch hơn câu trả lời được chấp nhận. Nó có thực hiện tốt không?
jophde

2
Tôi đã sử dụng nó một thời gian trong một vài ứng dụng khác nhau và không có vấn đề gì.
JustinMorris

3
Nếu bạn muốn có một ảnh chụp màn hình của điện thoại, nơi ứng dụng của bạn ở chế độ nền, bạn sẽ vượt qua điều viewgì? `
AlikElzin-kilaka

2
Chuyển qua getWindow().getDecorView().getRootView()khi xem kết quả trong việc chụp ảnh màn hình của ứng dụng - không phải màn hình.
AlikElzin-kilaka

Câu trả lời này chỉ có một ảnh chụp màn hình của ứng dụng - không phải là "màn hình điện thoại" như được hỏi trong câu hỏi - hoặc tôi đang làm gì đó sai.
AlikElzin-kilaka

42

Lưu ý: chỉ hoạt động cho điện thoại đã root

Lập trình, bạn có thể chạy adb shell /system/bin/screencap -p /sdcard/img.pngnhư dưới đây

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

sau đó đọc img.pngnhư Bitmapvà sử dụng như mong muốn của bạn.


Có cần truy cập root?
phóng to

3
Có bạn cần truy cập root. Vui lòng kiểm tra Ghi chú ở tiêu đề
Viswanath Lekshmanan

Xin chào, tôi có một System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , thiết bị của tôi là Android 5.0
Eddy

@Eddy Nó phụ thuộc vào thiết bị của bạn
Demian

Có cách nào để đọc đầu ra trực tiếp mà không lưu kết quả vào tập tin sau đó đọc lại không? stackoverflow.com/questions/43914035
Yazan W Yusuf

35

EDIT: có lòng thương xót với các downvote. Đó là sự thật vào năm 2010 khi tôi trả lời câu hỏi.

Tất cả các chương trình cho phép ảnh chụp màn hình chỉ hoạt động trên điện thoại đã root.


Có vẻ như những ngày này có thể có trên Android với chipset dựa trên Tegra
GDR

4.0.3 - sau đó có lẽ là một trong những máy tính bảng tegra trường học mới
GDR

AFAIK khi các thiết bị có ứng dụng chứng khoán để chụp ảnh màn hình, đó là một ứng dụng có các đặc quyền chữ ký đặc biệt cho phép nó chụp bộ đệm khung (bộ đệm có chứa các pixel màn hình). Vì vậy, sự thật là, nếu ROM của bạn có một ứng dụng như vậy, bạn sẽ không cần phải root, nhưng chỉ ứng dụng đó mới có thể tạo ra các ảnh chụp chứ không phải của bạn.
Rui Marques

2
Nói đúng ra, cùng với tài khoản người dùng "shell" của ADB luôn có quyền làm điều này vì đó là trường hợp sử dụng dự định. Những gì không có sẵn trong lịch sử (ngoại trừ các bản dựng thỉnh thoảng là một lỗi) là một cách để id người dùng ứng dụng làm như vậy.
Chris Stratton

26

Không có quyền root hoặc không có mã hóa lớn được yêu cầu cho phương pháp này.


Trên vỏ adb bằng lệnh bên dưới, bạn có thể chụp ảnh màn hình.

input keyevent 120

Lệnh này không yêu cầu bất kỳ quyền root nào vì vậy bạn cũng có thể thực hiện từ mã java của ứng dụng Android.

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

Tìm hiểu thêm về mã khóa trong Android, hãy xem http://developer.android.com/reference/android/view/KeyEvent.html

Ở đây chúng tôi đã sử dụng. KEYCODE_SYSRQ giá trị của nó là 120 và được sử dụng cho phím Yêu cầu hệ thống / Màn hình in.


Như CJBS đã nói, hình ảnh đầu ra sẽ được lưu trong / sdcard / Ảnh / Ảnh chụp màn hình


Hình ảnh đầu ra sẽ được lưu tại đây:/sdcard/Pictures/Screenshots
CJBS

nó có cần sự cho phép root không ??
Taranmeet Singh

1
nó sẽ hoạt động trên marshmallow? hoặc nó sẽ hoạt động trong nền dịch vụ @JeegarPatel
karanatwal.github.io 6/12/2016

2
không làm việc theo chương trình, nhưng hoạt động từ vỏ. Đã thử với kẹo dẻo.
mehmet6parmak

1
su -c "input keyevent 120"được chứ !!
ipcjs

17

Câu trả lời của Mualig rất hay, nhưng tôi có cùng một vấn đề mà Ewoks mô tả, tôi không nhận được nền tảng. Vì vậy, đôi khi là đủ tốt và đôi khi tôi nhận được văn bản màu đen trên nền đen (tùy thuộc vào chủ đề).

Giải pháp này chủ yếu dựa vào mã Mualig và mã tôi đã tìm thấy trong Robotium. Tôi đang loại bỏ việc sử dụng bộ đệm vẽ bằng cách gọi trực tiếp đến phương thức vẽ. Trước đó, tôi sẽ cố gắng lấy nền có thể vẽ từ hoạt động hiện tại để vẽ nó trước.

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

Tôi có một listview với android: cacheColorHint = "# 00000000" trong hoạt động của mình và tôi sử dụng mã này để chụp màn hình, tôi vẫn có nền đen, vì tôi thấy nền đó lấy từ chủ đề là màu đen, làm cách nào tôi có thể xử lý vấn đề này nghe?
Wangchao0721

Hoạt động hoạt động = getCienActivity cho Eroor phương thức không xác định.
Shabbir Dhangot

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

Thêm quyền trong tệp kê khai

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

Để hỗ trợ Marshmallow hoặc các phiên bản trên, vui lòng thêm mã dưới đây vào phương thức hoạt động onCreate

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);

Yêu cầu: <used-allow android: name = "ERIC.WRITE_EXTERNAL_STORAGE" />
AndroidGuy

4
Câu trả lời này chụp ảnh màn hình của ứng dụng - không phải là "màn hình điện thoại" như được hỏi trong câu hỏi - hoặc tôi đang làm gì sai?
AlikElzin-kilaka

Nếu tôi cần ảnh chụp màn hình của một mục listview thì sao?
Anshul Tyagi

tôi muốn nắm bắt từ bộ chuyển đổi bất kỳ ý tưởng làm thế nào tôi có thể làm điều đó?
Sâu Dave

16

Để tham khảo, một cách để chụp màn hình (và không chỉ hoạt động ứng dụng của bạn) là chụp bộ đệm khung (thiết bị / dev / đồ họa / fb0). Để làm điều này, bạn phải có quyền root hoặc ứng dụng của bạn phải là một ứng dụng có quyền chữ ký ("Quyền mà hệ thống chỉ cấp nếu ứng dụng yêu cầu được ký với cùng chứng chỉ với ứng dụng đã khai báo quyền") - đó là rất khó xảy ra trừ khi bạn biên dịch ROM của riêng bạn.

Mỗi lần chụp bộ đệm khung, từ một vài thiết bị tôi đã thử nghiệm, chứa chính xác một ảnh chụp màn hình. Mọi người đã báo cáo nó chứa nhiều hơn, tôi đoán nó phụ thuộc vào kích thước khung hình / màn hình.

Tôi đã cố gắng đọc bộ đệm khung liên tục nhưng nó dường như trả về một lượng byte cố định đã đọc. Trong trường hợp của tôi đó là (3 410 432) byte, đủ để lưu trữ khung hiển thị 854 * 480 RGBA (3 279 360 byte). Có, khung, ở dạng nhị phân, xuất ra từ fb0 là RGBA trong thiết bị của tôi. Điều này rất có thể sẽ phụ thuộc từ thiết bị này đến thiết bị khác. Điều này sẽ rất quan trọng để bạn giải mã nó =)

Trong quyền của thiết bị / dev / Graphics / fb0 của tôi là để chỉ root và người dùng từ đồ họa nhóm có thể đọc fb0.

đồ họa là một nhóm bị hạn chế, do đó bạn có thể sẽ chỉ truy cập fb0 bằng điện thoại đã root bằng lệnh su.

Các ứng dụng Android có id người dùng (uid) = app _ ##id nhóm (guide) = app _ ## .

adb shelluid = shellguide = shell , có nhiều quyền hơn một ứng dụng. Bạn thực sự có thể kiểm tra các quyền đó tại / system / permissions / pl platform.xml

Điều này có nghĩa là bạn sẽ có thể đọc fb0 trong shell adb mà không cần root nhưng bạn sẽ không đọc nó trong ứng dụng mà không cần root.

Ngoài ra, việc cấp quyền READ_FRAME_BUFFER và / hoặc ACCESS_SURFACE_FLinger trên AndroidManifest.xml sẽ không làm được gì cho một ứng dụng thông thường vì những điều này sẽ chỉ hoạt động cho các ứng dụng ' chữ ký '.

Ngoài ra kiểm tra chủ đề kín này để biết thêm chi tiết.


2
Điều này hoạt động (hoạt động?) Trên một số điện thoại, nhưng lưu ý rằng điện thoại dựa trên GPU không nhất thiết phải cung cấp bộ đệm khung tuyến tính cho bộ xử lý ứng dụng.
Chris Stratton

15

Giải pháp của tôi là:

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

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

Hình ảnh được lưu trong thư mục lưu trữ ngoài.


1
Bạn nên đóng FileOutputStream trong một khối cuối cùng. Nếu bạn gặp một ngoại lệ bây giờ, luồng sẽ không bị đóng.
Wotuu

Bạn viewđang đi qua ImageUtils.loadBitmapFromView(this, view)cái gì vậy?
AlikElzin-kilaka

1
tại sao bạn sử dụng v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ()); ? Điều đó không thay đổi quan điểm (v)?
serj

11

Bạn có thể thử thư viện sau: http://code.google.com.vn/p/android-sc Muff- l Library / Thư viện ảnh chụp màn hình Android (ASL) cho phép chụp ảnh màn hình từ các thiết bị Android theo chương trình mà không yêu cầu phải có quyền truy cập root. Thay vào đó, ASL sử dụng một dịch vụ gốc chạy trong nền, được bắt đầu thông qua Cầu gỡ lỗi Android (ADB) một lần cho mỗi lần khởi động thiết bị.


1
Tôi đã thử cái này. Nhưng nó chỉ chụp ảnh màn hình của ứng dụng đang chạy. Nó không thể giúp nếu tôi muốn chụp ảnh màn hình của màn hình chính. Bạn có làm thế nào để chụp ảnh màn hình của mã màn hình với mã đó không?
Jana

1
@ Janardhanan.S: Đây là những gì câu hỏi đang yêu cầu. Bạn có thể giải thích với một câu trả lời mới thay vì hỏi một câu hỏi riêng biệt.
trgraglia

3
Vấn đề tương tự với tôi .. "Dịch vụ bản địa không chạy !!"
Yogesh Maheshwari

1
Tương tự với tôi "Dịch vụ bản địa không chạy !!" .... có ai có thể thêm văn bản trợ giúp ở đây không?
Pankaj Kumar

1
tương tự ở đây "Dịch vụ bản địa không chạy !!" và trong phiên bản 1.2 mới nhất của họ, họ sử dụng các lớp API LEVEL 19, ví dụ như Socket.
user347187

10

Dựa trên câu trả lời của @JustinMorris ở trên và @NiravDangi tại đây https://stackoverflow.com/a/8504958/2 232148, chúng ta phải lấy nền và tiền cảnh của một chế độ xem và lắp ráp chúng như thế này:

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

Tham số chất lượng lấy hằng số Bitmap.Config, thường là Bitmap.Config.RGB_565hoặc Bitmap.Config.ARGB_8888.


vẽ canvas với màu trắng trong trường hợp nền là null đã lừa tôi. Cảm ơn Oliver
Shaleen

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

}

THÊM GIẤY PHÉP

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

Câu trả lời này chụp ảnh màn hình của ứng dụng - không phải là "màn hình điện thoại" như được hỏi trong câu hỏi - hoặc tôi đang làm gì sai?
AlikElzin-kilaka

7

Bạn có thể thử làm một cái gì đó như thế này,

Nhận bộ đệm bitmap từ bố cục hoặc chế độ xem bằng cách thực hiện một thao tác nào đó Trước tiên, bạn phải setDrawingCacheEnabledbố trí (linearlayout hoặc relat khóayout hoặc chế độ xem)

sau đó

Bitmap bm = layout.getDrawingCache()

Sau đó, bạn làm bất cứ điều gì bạn muốn với bitmap. Hoặc biến nó thành một tệp hình ảnh, hoặc gửi uri của bitmap đến một nơi khác.


1
Đây là phương pháp tốt nhất nếu đó là ứng dụng của bạn mà bạn đang viết lên bitmap. Ngoài ra, hãy cẩn thận với các phương thức có độ trễ trước khi lấy bộ đệm ... như Thông báo ... () cho chế độ xem danh sách.
trgraglia

Không chỉ co điêu đo. Bố cục phải được hiển thị trên màn hình đầu tiên. Đó là "bộ nhớ cache" bạn sẽ nhận được sau đó. Đã thử ẩn chế độ xem và chụp ảnh màn hình ở chế độ nền (về lý thuyết), nhưng nó không hoạt động.
Kevin Tan

Bởi hiệu quả hơn nhiều so với các giải pháp khác
sivi

6

Đối với những người muốn chụp GLSurfaceView, phương thức getDrawingCache hoặc vẽ sang canvas sẽ không hoạt động.

Bạn phải đọc nội dung của bộ đệm khung OpenGL sau khi khung được hiển thị. Có một câu trả lời tốt ở đây


6

Tôi đã tạo một thư viện đơn giản lấy ảnh chụp màn hình từ một Viewvà cung cấp cho bạn một đối tượng Bitmap hoặc lưu nó trực tiếp vào bất kỳ đường dẫn nào bạn muốn

https://github.com/abdallahalaraby / Liên kết


Có yêu cầu điện thoại root?
Nilesh Agrawal

1
Không cần root máy :)
Abdallah Alaraby 10/2/2015

Trong sử dụng u đã đề cập Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); Làm thế nào để có được cái nhìn của hoạt động hiện tại. Tôi không muốn sử dụng id của xml.
Nilesh Agrawal

sử dụng takeScreenshotForScreen()thay thế.
Abdallah Alaraby

6

Đường ngắn là

FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();

5

Chỉ cần mở rộng câu trả lời của taraloca. Bạn phải thêm các dòng sau để làm cho nó hoạt động. Tôi đã làm cho tên hình ảnh tĩnh. Vui lòng đảm bảo bạn sử dụng biến dấu thời gian của taraloca trong trường hợp bạn cần tên hình ảnh động.

    // Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

private void verifyStoragePermissions() {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
    }else{
        takeScreenshot();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == REQUEST_EXTERNAL_STORAGE) {
            takeScreenshot();
        }
    }
}

Và trong tệp AndroidManifest.xml, các mục sau đây phải:

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

4

Nếu bạn muốn chụp ảnh màn hình từ fragment hơn hãy làm theo điều này:

  1. Ghi đè 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;
            }
  2. Logic chụp ảnh màn hình:

     button.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
         View view =  mView.findViewById(R.id.scrollView1);
          shareScreenShotM(view, (NestedScrollView) view); 
     }
  3. phương pháp 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.
        }
  4. phương thức 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;
            }
  5. phương thức 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;
       }

Đối với hoạt động bạn chỉ cần sử dụng View v1 = getWindow().getDecorView().getRootView();thay vìmView


3

Hầu hết các câu trả lời cho câu hỏi này sử dụng Canvasphương pháp vẽ hoặc phương pháp vẽ bộ đệm. Tuy nhiên, View.setDrawingCache()phương pháp không được dùng trong API 28 . Hiện tại API được đề xuất để tạo ảnh chụp màn hình là PixelCopylớp có sẵn từ API 24 (nhưng các phương thức chấp nhận Windowtham số có sẵn từ API 26 == Android 8.0 Oreo). Dưới đây là mã Kotlin mẫu để truy xuất a Bitmap:

@RequiresApi(Build.VERSION_CODES.O)
fun saveScreenshot(view: View) {
    val window = (view.context as Activity).window
    if (window != null) {
        val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
        val locationOfViewInWindow = IntArray(2)
        view.getLocationInWindow(locationOfViewInWindow)
        try {
            PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
                if (copyResult == PixelCopy.SUCCESS) {
                    saveBitmap(bitmap)
                }
                // possible to handle other result codes ...
            }, Handler())
        } catch (e: IllegalArgumentException) {
            // PixelCopy may throw IllegalArgumentException, make sure to handle it
        }
    }
}

Vấn đề với PixelCopy so với giải pháp drawCache là nó dường như chỉ chụp pixel hiển thị. Phần còn lại là màu đen đối với tôi. Vì vậy, không thể chia sẻ những thứ có thể cuộn được và một phần nằm ngoài khung. Bạn có một giải pháp cho việc này?
Henning

Bạn đúng rồi. Tương tự, nó có thể gây ra sự cố nếu Chế độ xem khác được hiển thị phía trên Chế độ xem tôi muốn chụp màn hình (ví dụ: khi ngăn kéo được mở). Trong những trường hợp này, tôi chỉ sử dụng phương thức Canvas cũ :(
Miloš ernilovský

1
Có thể chụp ảnh màn hình trên bất kỳ ứng dụng đang chạy nào bằng PixelCopy không?
Amir Rezaei

2

Chỉ dành cho các ứng dụng hệ thống!

Process process;
process = Runtime.getRuntime().exec("screencap -p " + outputPath);
process.waitFor();

Lưu ý: Các ứng dụng hệ thống không cần chạy "su" để thực thi lệnh này.


2

Khung nhìn tham số là đối tượng bố trí gốc.

public static Bitmap screenShot(View view) {
                    Bitmap bitmap = null;
                    if (view.getWidth() > 0 && view.getHeight() > 0) {
                        bitmap = Bitmap.createBitmap(view.getWidth(),
                                view.getHeight(), Bitmap.Config.ARGB_8888);
                        Canvas canvas = new Canvas(bitmap);
                        view.draw(canvas);
                    }
                    return bitmap;
                }

2

Đối với ảnh chụp màn hình toàn trang

Nếu bạn muốn chụp ảnh màn hình Xem đầy đủ (Có chứa cuộn xem hoặc hơn) thì hãy kiểm tra tại thư viện này

https://github.com/peter1492/LongSc mãi

Tất cả những gì bạn phải làm là nhập Gradel và tạo một đối tượng của BigSc mãi

BigScreenshot longScreenshot = new BigScreenshot(this, x, y);

Một cuộc gọi lại sẽ được nhận với bitmap của Ảnh chụp màn hình trong khi tự động cuộn qua nhóm xem màn hình và ở cuối được ghép lại với nhau.

@Override public void getScreenshot(Bitmap bitmap) {}

Mà có thể được lưu vào thư viện hoặc bất cứ việc sử dụng nào là cần thiết sau khi


1

Chụp ảnh màn hình của một chế độ xem trong Android.

public static Bitmap getViewBitmap(View v) {
    v.clearFocus();
    v.setPressed(false);

    boolean willNotCache = v.willNotCacheDrawing();
    v.setWillNotCacheDrawing(false);

    int color = v.getDrawingCacheBackgroundColor();
    v.setDrawingCacheBackgroundColor(0);

    if (color != 0) {
        v.destroyDrawingCache();
    }
    v.buildDrawingCache();
    Bitmap cacheBitmap = v.getDrawingCache();
    if (cacheBitmap == null) {
        return null;
    }

    Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);

    v.destroyDrawingCache();
    v.setWillNotCacheDrawing(willNotCache);
    v.setDrawingCacheBackgroundColor(color);

    return bitmap;
}

-1

nếu bạn muốn chụp một khung nhìn hoặc bố cục như RelativeLayout hoặc linearLayout, v.v. chỉ cần sử dụng mã:

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

bây giờ bạn có thể lưu bitmap này vào bộ nhớ thiết bị bằng cách:

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();}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.