50

重複の可能性:
Androidでプログラムでスクリーンショットを撮る方法は?

Androidデバイスの画面コンテンツをキャプチャし、スナップショットデータを使用して画像ファイルを作成するにはどうすればよいですか?どのAPIを使用する必要がありますか、または関連するリソースはどこにありますか?

ところで:カメラのスナップショットではなく、デバイスの画面

4

8 に答える 8

43

次のコードを使用します。

Bitmap bitmap;
View v1 = MyView.getRootView();
v1.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);

これが、画面に含める必要MyViewのあるスルーです。この方法で(なしで)View取得することもできます。DrawingCacheViewgetRootView()


別の方法もあります。ルートビューとして使用する
場合ScrollViewは、次のコードを使用することをお勧めします。

LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
FrameLayout root = (FrameLayout) inflater.inflate(R.layout.activity_main, null); // activity_main is UI(xml) file we used in our Activity class. FrameLayout is root view of my UI(xml) file.
root.setDrawingCacheEnabled(true);
Bitmap bitmap = getBitmapFromView(this.getWindow().findViewById(R.id.frameLayout)); // here give id of our root layout (here its my FrameLayout's id)
root.setDrawingCacheEnabled(false);

これがgetBitmapFromView()方法です

public static Bitmap getBitmapFromView(View view) {
        //Define a bitmap with the same size as the view
        Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
        //Bind a canvas to it
        Canvas canvas = new Canvas(returnedBitmap);
        //Get the view's background
        Drawable bgDrawable =view.getBackground();
        if (bgDrawable!=null) 
            //has background drawable, then draw it on the canvas
            bgDrawable.draw(canvas);
        else 
            //does not have background drawable, then draw white background on the canvas
            canvas.drawColor(Color.WHITE);
        // draw the view on the canvas
        view.draw(canvas);
        //return the bitmap
        return returnedBitmap;
    }

ScrollView


2016年4月20日に更新されたコンテンツに隠されたコンテンツを含む画面全体が表示されます

。スクリーンショットを撮る別のより良い方法があります。
ここで私はのスクリーンショットを撮りWebViewました。

WebView w = new WebView(this);
    w.setWebViewClient(new WebViewClient()
    {
        public void onPageFinished(final WebView webView, String url) {

            new Handler().postDelayed(new Runnable(){
                @Override
                public void run() {
                    webView.measure(View.MeasureSpec.makeMeasureSpec(
                                    View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
                            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                    webView.layout(0, 0, webView.getMeasuredWidth(),
                            webView.getMeasuredHeight());
                    webView.setDrawingCacheEnabled(true);
                    webView.buildDrawingCache();
                    Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(),
                            webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);

                    Canvas canvas = new Canvas(bitmap);
                    Paint paint = new Paint();
                    int height = bitmap.getHeight();
                    canvas.drawBitmap(bitmap, 0, height, paint);
                    webView.draw(canvas);

                    if (bitmap != null) {
                        try {
                            String filePath = Environment.getExternalStorageDirectory()
                                    .toString();
                            OutputStream out = null;
                            File file = new File(filePath, "/webviewScreenShot.png");
                            out = new FileOutputStream(file);

                            bitmap.compress(Bitmap.CompressFormat.PNG, 50, out);
                            out.flush();
                            out.close();
                            bitmap.recycle();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, 1000);
        }
    });

お役に立てれば..!

于 2011-12-14T13:04:48.787 に答える
23

AFAIK、現在Androidのスクリーンショットをキャプチャするすべてのメソッドは、/ dev / graphics/fb0フレームバッファーを使用します。これにはddmsが含まれます。このストリームから読み取るには、rootが必要です。ddmsはadbdを使用して情報を要求します。したがって、adbには/ dev / graphics / fb0からのデータを要求するために必要なアクセス許可があるため、rootは必要ありません。

フレームバッファには、RGB565画像の2つ以上の「フレーム」が含まれています。データを読み取ることができる場合は、画像を取得するために必要なバイト数を知るために、画面の解像度を知る必要があります。各ピクセルは2バイトです。したがって、画面解像度が480x800の場合、480x800 RGB565画像には384,000ピクセルがあるため、画像の768,000バイトを読み取る必要があります。

于 2010-06-18T13:21:38.690 に答える
22

新しいAndroidプラットフォームの場合、root権限なしでシステムユーティリティscreencapを実行してスクリーンショットを取得できます。adbまたは任意のシェルでの使用方法を確認/system/binできます。/system/bin/screencap -h

ちなみに、この方法はシングルスナップショットにのみ適していると思います。スクリーンプレイのために複数のフレームをキャプチャしたい場合は、遅すぎます。より高速な画面キャプチャのための他のアプローチが存在するかどうかはわかりません。

于 2012-06-11T09:50:28.487 に答える
18

[Androidソースコードに基づく:]

C ++側では、SurfaceFlingerはcaptureScreenAPIを実装します。これはバインダーIPCイン​​ターフェースを介して公開され、画面からの生のピクセルを含む新しいashmem領域が毎回返されます。実際のスクリーンショットはOpenGLを介して取得されます。

<surfaceflinger_client/SurfaceComposerClient.h>システムC++クライアントの場合、インターフェイスは、Android<4.1用に定義されたScreenshotClientクラスを介して公開されます。Android>4.1の使用<gui/SurfaceComposerClient.h>

JBの前は、C ++プログラムでスクリーンショットを撮るには、これで十分でした。

ScreenshotClient ssc;
ssc.update();

JBと複数のディスプレイを使用すると、少し複雑になります。

ssc.update(
    android::SurfaceComposerClient::getBuiltInDisplay(
        android::ISurfaceComposer::eDisplayIdMain));

次に、それにアクセスできます。

do_something_with_raw_bits(ssc.getPixels(), ssc.getSize(), ...);

Androidソースコードを使用して、独自の共有ライブラリをコンパイルしてそのAPIにアクセスし、JNIを介してJavaに公開できます。アプリからスクリーンショットを作成するには、アプリにREAD_FRAME_BUFFER権限が必要です。ただし、それでも、システムアプリケーション、つまりシステムと同じキーで署名されたアプリケーションからのみスクリーンショットを作成できるようです。(この部分は、Androidのアクセス許可システムに精通していないため、まだよくわかりません。)

JB 4.1/4.2のコードは次のとおりです。

#include <utils/RefBase.h>
#include <binder/IBinder.h>
#include <binder/MemoryHeapBase.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>

static void do_save(const char *filename, const void *buf, size_t size) {
    int out = open(filename, O_RDWR|O_CREAT, 0666);
    int len = write(out, buf, size);
    printf("Wrote %d bytes to out.\n", len);
    close(out);
}

int main(int ac, char **av) {
    android::ScreenshotClient ssc;
    const void *pixels;
    size_t size;
    int buffer_index;

    if(ssc.update(
        android::SurfaceComposerClient::getBuiltInDisplay(
            android::ISurfaceComposer::eDisplayIdMain)) != NO_ERROR ){
        printf("Captured: w=%d, h=%d, format=%d\n");
        ssc.getWidth(), ssc.getHeight(), ssc.getFormat());
        size = ssc.getSize();
        do_save(av[1], pixels, size);
    }
    else
        printf(" screen shot client Captured Failed");
    return 0;
}
于 2011-11-02T10:55:00.337 に答える
15

次のライブラリを試すことができます。Androidスクリーンショットライブラリ(ASL)を使用すると、rootアクセス権限がなくても、Androidデバイスからプログラムでスクリーンショットをキャプチャできます。代わりに、ASLは、デバイスの起動ごとに1回、Android Debug Bridge(ADB)を介して開始されるバックグラウンドで実行されるネイティブサービスを利用します。

于 2010-09-07T14:06:50.377 に答える
13

このリンクによると、Android SDKのツールディレクトリにあるddmsを使用して、画面をキャプチャすることができます。

アプリケーション内で(開発中ではなく)これを行うために、そうするアプリケーションもあります。しかし、@ zed_0xffが指摘しているように、それは確かにルートを必要とします。

于 2010-06-18T09:02:11.983 に答える
7

フレームバッファは進むべき道のようです。ライアンコンラッドが述べたように、常に2つ以上のフレームが含まれるとは限りません。私の場合、1つしか含まれていませんでした。フレーム/ディスプレイのサイズにもよると思います。

フレームバッファを継続的に読み取ろうとしましたが、一定量のバイトを読み取った場合に返されるようです。私の場合、それは(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シェルにはuidシェルguidシェルがあり、アプリよりもはるかに多くの権限があります。これらの権限は/system/permissions/platform.xmlで実際に確認できます

つまり、rootなしでadbシェルでfb0を読み取ることはできますが、rootなしでアプリ内で読み取ることはできません。

また、AndroidManifest.xmlでREAD_FRAME_BUFFERやACCESS_SURFACE_FLINGER権限を付与しても、通常のアプリでは何も行われません。これらは「署名」アプリでのみ機能するためです。

于 2012-08-31T18:12:41.407 に答える
5

AndroidアプリAFAIKでJavaコードから画面キャプチャを実行する場合は、ルート権限が必要です。

于 2010-06-18T09:08:10.473 に答える