프로그래밍 방식으로 Android에서 스크린 샷을 찍는 방법은 무엇입니까?


495

프로그램에서가 아니라 코드에서 선택한 전화 화면 영역의 스크린 샷을 어떻게 찍을 수 있습니까?


4
에뮬레이터가 아닙니다. 내 프로그램의 일부 스크린 샷을 만들고 동일한 프로그램에서 smth로 수행해야합니다.
— korovaisdead


답변:


448

다음은 내 스크린 샷을 SD 카드에 저장하고 나중에 필요에 따라 사용할 수있는 코드입니다.

먼저 파일을 저장할 수있는 적절한 권한을 추가해야합니다.

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

그리고 이것은 (활동에서 실행되는) 코드입니다.

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

그리고 이것은 최근에 생성 된 이미지를 여는 방법입니다 :

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

조각보기에서 이것을 사용하려면 다음을 사용하십시오.

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

대신에

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

에 takeScreenshot () 함수

참고 :

대화 상자에 표면 뷰가 포함되어 있으면이 솔루션이 작동하지 않습니다. 자세한 내용은 다음 질문에 대한 답변을 확인하십시오.

Surface View의 Android 스크린 샷에 검은 색 화면 표시


23
안녕하세요, mCurrentUrlMask 란 무엇입니까? 이 코드를 시도했지만 항상 Bitmap.createBitmap (v1.getDrawingCache ())에서 NullPointerException이 발생합니다. 누군가 내가 뭘 잘못했는지 말할 수 있습니까? 도움을 주시면 감사하겠습니다. 감사.
— Mitesh Sardhara

4
@MiteshSardhara mCurrentUrlMask는 ViewAndroid API에서 getRootView()메소드 가있는 고유 한 클래스 여야합니다 . 아마도 UI의 관점 일 것입니다.
— gipi

6
mCurrentUrlMask 란 무엇입니까?
— Jayeshkumar Sojitra

37
의 Insted View v1 = mCurrentUrlMask.getRootView();내가 사용하고 View v1 = getWindow().getDecorView().getRootView();그것은 나를 위해 작동합니다.
— enadun

9
이 답변은 질문에 표시된 "전화 화면"이 아닌 응용 프로그램의 스크린 샷을 찍거나 잘못된 일을하고 있습니까?
— AlikElzin-kilaka

126

이 메소드를 호출하여 스크린 샷을 원하는 가장 많은 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;
}

9
이것은 허용 된 답변보다 깨끗한 코드 인 것 같습니다. 성능도 좋아?
— jophde

2
몇 가지 다른 앱에서 한동안 사용했지만 아무런 문제가 없었습니다.
— JustinMorris

3
앱이 백그라운드에있는 전화의 스크린 샷을 얻고 싶은 경우에, 당신은으로 무엇을 전달하지 view`?
— AlikElzin-kilaka

2
getWindow().getDecorView().getRootView()보기로 전달 하면 화면이 아닌 앱의 스크린 샷이 생성됩니다.
— AlikElzin-kilaka

이 답변은 질문에 표시된 "전화 화면"이 아닌 응용 프로그램의 스크린 샷을 찍거나 잘못된 일을하고 있습니까?
— AlikElzin-kilaka

42

참고 : 루팅 된 전화에 대해서만 작동

프로그래밍 방식 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();    

다음 읽기 img.png로 Bitmap하고 당신의 소원으로 사용합니다.


루트 액세스가 필요합니까?
— 확대

3
예, 루트 액세스 권한이 필요합니다. 제목에서 메모를 확인하십시오
— Viswanath Lekshmanan

안녕, 나는 System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null 내 장치는 안드로이드 5.0입니다
— Eddy

@Eddy 기기에 따라 다릅니다.
— Demian

결과를 파일로 저장 한 다음 다시 읽지 않고 출력을 직접 읽는 방법이 있습니까? stackoverflow.com/questions/43914035
— Yazan W Yusuf

35

편집 : downvotes에 자비를 베푸십시오. 내가 질문에 대답했을 때 2010 년에 사실이었습니다.

스크린 샷을 허용하는 모든 프로그램은 루팅 된 휴대 전화에서만 작동합니다.


요즘 Tegra 기반 칩셋을 사용하는 Android에서 가능할 것으로 보입니다.
— GDR

4.0.3-그렇다면 아마도이 새로운 테그 라 태블릿 중 하나 일 것입니다
— GDR

AFAIK 기기에 스크린 샷을 캡처 할 스톡 앱이있는 경우 프레임 버퍼 (스크린 픽셀이 포함 된 버퍼)를 캡처 할 수있는 특별한 서명 권한이있는 앱입니다. 따라서 ROM에 그러한 앱이있는 경우 루팅 할 필요는 없지만 해당 앱만 캡처 할 수 있지만 캡처 할 수는 없습니다.
— Rui Marques

2
엄밀히 말하면 루트 ADB의 "쉘"사용자 계정과 함께 의도 된 사용 사례이므로 항상이 작업을 수행 할 권한이 있습니다. 역사적으로 사용할 수 없었던 것은 (실수로 실수로 빌드 한 경우는 제외하고) 응용 프로그램 사용자 ID의 방법이었습니다 .
— Chris Stratton

26

이 방법 에는 루트 권한 이나 큰 코딩 이 필요 하지 않습니다 .


아래 명령을 사용하여 adb shell에서 스크린 샷을 찍을 수 있습니다.

input keyevent 120

이 명령은 루트 권한이 필요하지 않으므로 Android 애플리케이션의 Java 코드에서도 수행 할 수 있습니다.

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

안드로이드의 주요 이벤트 코드에 대한 자세한 내용은 http://developer.android.com/reference/android/view/KeyEvent.html을 참조 하십시오.

여기에 우리가 사용했습니다. KEYCODE_SYSRQ 값은 120이며 시스템 요청 / 인쇄 화면 키에 사용됩니다.


CJBS가 말했듯이 출력 사진은 / sdcard / Pictures / Screenshots에 저장됩니다


출력 사진이 여기에 저장됩니다 :/sdcard/Pictures/Screenshots
— CJBS

루트 권한이 필요합니까 ??
— Taranmeet Singh 5

1
마시멜로에서 작동합니까? 아니면 서비스 배경에서 작동합니까 @JeegarPatel
— karanatwal.github.io

2
프로그래밍 방식으로 작동하지 않지만 쉘에서 작동합니다. 누가와 함께 시도했다.
— mehmet6parmak

1
su -c "input keyevent 120"괜찮아 !!
— ipcjs

17

Mualig의 대답은 매우 좋지만 Ewoks가 설명하는 것과 같은 문제가 있었지만 배경을 얻지 못했습니다. 그래서 때로는 충분하고 때로는 테마에 따라 검은 배경 위에 검은 색 텍스트가 나타납니다.

이 솔루션은 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();
}

내 활동에 android : cacheColorHint = "# 00000000"이있는 목록보기가 있고이 코드를 스크린 샷에 사용합니다. 테마에서 가져온 배경이 검은 색이라는 것을 알았으므로 여전히 검은 색 배경을 얻었습니다. 목록보기?
— Wangchao0721

활동 활동 = getCurrentActivity는 Eroor에 정의되지 않은 메소드를 제공합니다.
— 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();
    }
}

매니페스트에 권한 추가

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

Marshmallow 이상 버전을 지원 하려면 onCreate 메소드 활동에 아래 코드를 추가하십시오.

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

요구 사항 : <uses-permission android : name = "android.permission.WRITE_EXTERNAL_STORAGE"/>
— AndroidGuy

4
이 답변은 질문에 표시된 "전화 화면"이 아닌 응용 프로그램의 스크린 샷을 찍습니다. 또는 잘못된 일이 있습니까?
— AlikElzin-kilaka

listview 항목의 스크린 샷이 필요한 경우 어떻게해야합니까?
— Anshul Tyagi

어댑터에서 캡처하고 싶습니다. 어떻게 할 수 있습니까?
— Deep Dave

16

참고로 앱 활동이 아닌 화면을 캡처하는 한 가지 방법은 프레임 버퍼 (장치 / dev / graphics / fb0) 를 캡처하는 것 입니다. 이렇게하려면 루트 권한이 있거나 앱에 서명 권한 이있는 앱이어야합니다 ( "요청한 응용 프로그램이 권한을 선언 한 응용 프로그램과 동일한 인증서로 서명 한 경우에만 시스템이 부여하는 권한")- 자신의 ROM을 컴파일하지 않는 한 매우 가능성이 낮습니다.

내가 테스트 한 몇 가지 장치의 각 프레임 버퍼 캡처에는 정확히 하나의 스크린 샷이 포함되어 있습니다. 사람들은 더 많이 포함한다고보고했습니다. 프레임 / 디스플레이 크기에 달려 있다고 생각합니다.

프레임 버퍼를 계속 읽으려고했지만 고정 된 양의 바이트를 읽은 것으로 반환됩니다. 제 경우에는 (3 410 432) 바이트로 854 * 480 RGBA (3 279360 바이트)의 디스플레이 프레임을 저장하기에 충분합니다. 예, fb0에서 출력되는 이진 단위의 프레임 은 내 장치의 RGBA 입니다. 이것은 대부분 장치마다 다릅니다. 이것을 해독하는 것이 중요합니다 =)

내 장치에서 / dev / graphics / fb0 권한은 그룹 그래픽의 루트 및 사용자 만 fb0을 읽을 수 있도록합니다.

제도법 는 제한된 그룹이므로 su 명령을 사용하여 루팅 된 전화로만 fb0에 액세스 할 수 있습니다.

Android 앱의 사용자 ID (uid) = app _ ## 및 그룹 ID (guid) = app _ ## 입니다.

adb 쉘 에는 uid = shell이 있으며 guid = shell이 있으며 이는 앱보다 훨씬 많은 권한을 가지고 있습니다. /system/permissions/platform.xml에서 실제로 해당 권한을 확인할 수 있습니다.

이것은 루트없이 adb 쉘에서 fb0을 읽을 수 있지만 루트가없는 앱에서는 읽을 수 없다는 것을 의미합니다.

또한 AndroidManifest.xml에 대한 READ_FRAME_BUFFER 및 / 또는 ACCESS_SURFACE_FLINGER 권한을 부여하면 일반 앱에는 아무런 영향을 미치지 않습니다. 서명 '앱 .

자세한 내용은 이 스레드 를 확인하십시오.


2
일부 전화에서는 작동하지만 작동하지만 GPU 기반 전화는 반드시 응용 프로그램 프로세서에 선형 프레임 버퍼를 제공하지는 않습니다.
— Chris Stratton

15

내 해결책은 다음과 같습니다.

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

이미지는 외부 저장 폴더에 저장됩니다.


1
finally 블록에서 FileOutputStream을 닫아야합니다. 예외가 발생하면 스트림이 닫히지 않습니다.
— Wotuu

view당신은 무엇을 전달하고 ImageUtils.loadBitmapFromView(this, view)있습니까?
— AlikElzin-kilaka

1
왜 v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ())를 사용합니까? ? 뷰가 바뀌지 않습니까 (v)?
— serj

11

다음 라이브러리를 사용해 볼 수 있습니다. http://code.google.com/p/android-screenshot-library/ ASL (Android Screenshot Library)을 사용하면 루트 액세스 권한이 없어도 Android 기기에서 스크린 샷을 프로그래밍 방식으로 캡처 할 수 있습니다. 대신 ASL은 백그라운드에서 실행되는 기본 서비스를 사용하며 장치 부팅마다 한 번씩 Android 디버그 브리지 (ADB)를 통해 시작됩니다.


1
나는 이것을 시도했지만 실행중인 응용 프로그램의 스크린 샷을 찍습니다. 홈 화면의 스크린 샷을 찍고 싶을 때 도움이되지 않습니다. 해당 코드로 홈 화면의 스크린 샷을 만드는 방법은 무엇입니까?
— Jana

1
@ Janardhanan. S : 이것이 질문하는 것입니다. 별도의 질문을하는 대신 새로운 답변을 구사할 수 있습니까?
— trgraglia

3
저도 같은 문제입니다. "기본 서비스가 실행되지 않습니다 !!"
— Yogesh Maheshwari

1
저와 동일하게 "Native Service Not Running !!".... 여기에 도움말 텍스트를 추가 할 수 있습니까?
— Pankaj Kumar

1
여기 동일! "기본 서비스가 실행되지 않습니다 !!" 최신 버전 1.2에서는 예를 들어 Socket과 같은 API LEVEL 19 클래스를 사용합니다.
— user347187

10

위의 @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;
}

quality 매개 변수는 Bitmap.Config 상수 (일반적으로 Bitmap.Config.RGB_565또는)를 사용 Bitmap.Config.ARGB_8888합니다.


배경이 null 인 경우 흰색으로 캔버스를 그리는 것은 속임수입니다. 감사합니다 올리버
— 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();
}

}

권한 추가

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

이 답변은 질문에 표시된 "전화 화면"이 아닌 응용 프로그램의 스크린 샷을 찍습니다. 또는 잘못된 일이 있습니까?
— AlikElzin-kilaka

7

이런 식으로 할 수 있습니다

레이아웃이나 뷰에서 비트 맵 캐시 가져 오기 setDrawingCacheEnabled 레이아웃 (linearlayout 또는 relativelayout 또는 view)으로 이동 합니다

그때

Bitmap bm = layout.getDrawingCache()

그런 다음 비트 맵으로 원하는 것을 수행하십시오. 이미지 파일로 바꾸거나 비트 맵의 ​​URI를 다른 곳으로 보내십시오.


1
비트 맵에 쓰고있는 앱인 경우이 방법이 가장 좋습니다. 또한 캐시를 가져 오기 전에 지연되는 메소드를주의하십시오. 목록보기의 경우 Notify ... ()와 같습니다.
— trgraglia

뿐만 아니라. 레이아웃은 먼저 화면에 표시되어야합니다. 결국 "캐시"입니다. 뷰를 숨기고 백그라운드에서 스크린 샷을 찍으려고했지만 이론적으로 작동하지 않았습니다.
— 케빈 탄

다른 솔루션보다 훨씬 효율적
— sivi

6

GLSurfaceView를 캡처하려는 경우 getDrawingCache 또는 캔버스로 그리기 메소드가 작동하지 않습니다.

프레임이 렌더링 된 후 OpenGL 프레임 버퍼의 내용을 읽어야합니다. 여기에 좋은 대답이 있습니다


6

스크린 샷을 가져 와서 View비트 맵 객체를 제공하거나 원하는 경로에 직접 저장 하는 간단한 라이브러리를 만들었습니다.

https://github.com/abdallahalaraby/Blink


루팅 된 전화가 필요합니까?
— Nilesh Agrawal

1
응원 필요 없음 :)
— Abdallah Alaraby

사용법 Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); 에서 현재 활동을 보는 방법을 언급했습니다 . XML의 ID를 사용하고 싶지 않습니다.
— Nilesh Agrawal

사용하는 takeScreenshotForScreen()대신.
— Abdallah Alaraby

6

짧은 방법은

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

5

taraloca의 답변을 확장하는 것입니다. 작동하려면 다음 줄을 추가해야합니다. 이미지 이름을 정적으로 만들었습니다. 동적 이미지 이름이 필요한 경우 taraloca의 타임 스탬프 변수를 사용하십시오.

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

그리고 AndroidManifest.xml 파일에서 다음 항목이 있어야합니다.

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

4

fragment 다음보다 스크린 샷을 찍으려면 다음을 수행하십시오.

  1. 무시 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. 스크린 샷 찍기위한 논리 :

     button.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
         View view =  mView.findViewById(R.id.scrollView1);
          shareScreenShotM(view, (NestedScrollView) view); 
     }
  3. 방법 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. 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. 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;
       }

활동을 위해 View v1 = getWindow().getDecorView().getRootView();대신 대신 사용할 수 있습니다mView


3

이 질문에 대한 대부분의 답변은 Canvas그리기 방법 또는 그리기 캐시 방법을 사용합니다. 그러나이 View.setDrawingCache()메소드는 API 28에서 더 이상 사용되지 않습니다 . 현재 스크린 샷을 만드는 데 권장되는 API PixelCopy는 API 24에서 사용할 수 있는 클래스이지만 Window매개 변수 를 허용하는 메서드 는 API 26 == Android 8.0 Oreo에서 사용할 수 있습니다. 다음은 다음을 검색하기위한 Kotlin 코드 샘플입니다 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
        }
    }
}

drawingCache 솔루션의 PixelCopy 문제는 보이는 픽셀 만 캡처하는 것 같습니다. 나머지는 나를 위해 검은 색입니다. 따라서 스크롤 가능하고 부분적으로 벗어난 내용은 공유 할 수 없습니다. 이에 대한 해결책이 있습니까?
— Henning

네 말이 맞아 마찬가지로 스크린 샷을 보려는보기 위에 다른보기가 표시되면 (예 : 서랍을 열 때) 문제가 발생할 수 있습니다. 이러한 경우에는 그냥 오래된 캔버스 방법 :( 사용
— 밀로스 Černilovský

1
PixelCopy를 사용하여 실행중인 앱에서 스크린 샷을 찍을 수 있습니까?
— Amir Rezaei 님이

2

시스템 응용 프로그램 전용!

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

참고 : 시스템 응용 프로그램은이 명령을 실행하기 위해 "su"를 실행할 필요가 없습니다.


2

매개 변수보기는 루트 레이아웃 객체입니다.

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

전체 페이지 스크롤 스크린 샷

전체보기 스크린 샷을 캡처하려면 (스크롤 뷰가 포함되어있는 경우)이 라이브러리를 확인하십시오

https://github.com/peter1492/LongScreenshot

Gradel을 가져 와서 BigScreenshot 오브젝트를 작성하기 만하면됩니다.

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

스크린 뷰 그룹을 통해 자동으로 스크롤하는 동안 캡쳐 된 스크린 샷의 비트 맵과 함께 콜백이 수신되고 끝에서 함께 조립됩니다.

@Override public void getScreenshot(Bitmap bitmap) {}

갤러리에 저장할 수 있거나 그 이후의 사용법이 필요합니다.


1

안드로이드 뷰의 스크린 샷을 찍습니다.

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

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();}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.