web-dev-qa-db-ja.com

GLSurfaceViewの画面をビットマップにキャプチャ

特定の瞬間にGLSurfaceViewの画像をキャプチャできるようにする必要があります。私は次のコードを持っています:

relative.setDrawingCacheEnabled(true);
screenshot = Bitmap.createBitmap(relative.getDrawingCache());
relative.setDrawingCacheEnabled(false);
Log.v(TAG, "Screenshot height: " + screenshot.getHeight());
image.setImageBitmap(screenshot); 

GLSurfaceViewRelativeLayout内に含まれていますが、GLSurfaceViewを使用して画像を直接キャプチャしてみます。これにより、画面は透明な画像、つまり何もないものをキャプチャすると思います。どんな助けでもありがたいです。

35
SamRowley

SurfaceViewおよびGLSurfaceViewは、ウィンドウを開けて、サーフェスを表示できるようにします。つまり、透明な領域があります。

したがって、GLSurfaceView.getDrawingCache()を呼び出して画像をキャプチャすることはできません。

GLSurfaceViewからイメージを取得する場合は、gl.glReadPixels()GLSurfaceView.onDrawFrame()を呼び出す必要があります。

createBitmapFromGLSurfaceメソッドにパッチを適用し、onDrawFrame()で呼び出します。

(元のコードは skuld のコードからのものである可能性があります。)

private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl)
        throws OutOfMemoryError {
    int bitmapBuffer[] = new int[w * h];
    int bitmapSource[] = new int[w * h];
    IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
    intBuffer.position(0);

    try {
        gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);
        int offset1, offset2;
        for (int i = 0; i < h; i++) {
            offset1 = i * w;
            offset2 = (h - i - 1) * w;
            for (int j = 0; j < w; j++) {
                int texturePixel = bitmapBuffer[offset1 + j];
                int blue = (texturePixel >> 16) & 0xff;
                int red = (texturePixel << 16) & 0x00ff0000;
                int pixel = (texturePixel & 0xff00ff00) | red | blue;
                bitmapSource[offset2 + j] = pixel;
            }
        }
    } catch (GLException e) {
        return null;
    }

    return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
}
48
Dalinaum

レイアウトで定義されたGLSurfaceViewを「渡す」だけのサードパーティライブラリを使用している場合の完全なソリューションを次に示します。レンダラーのonDrawFrame()にはハンドルがありません。これは問題になる可能性があります...

これを行うには、GLSurfaceViewが処理するようにキューに入れる必要があります。

private GLSurfaceView glSurfaceView; // findById() in onCreate
private Bitmap snapshotBitmap;

private interface BitmapReadyCallbacks {
    void onBitmapReady(Bitmap bitmap);
}

/* Usage code
   captureBitmap(new BitmapReadyCallbacks() {

        @Override
        public void onBitmapReady(Bitmap bitmap) {
            someImageView.setImageBitmap(bitmap);
        }
   });
*/

// supporting methods
private void captureBitmap(final BitmapReadyCallbacks bitmapReadyCallbacks) {
    glSurfaceView.queueEvent(new Runnable() {
        @Override
        public void run() {
            EGL10 egl = (EGL10) EGLContext.getEGL();
            GL10 gl = (GL10)egl.eglGetCurrentContext().getGL();
            snapshotBitmap = createBitmapFromGLSurface(0, 0, glSurfaceView.getWidth(), glSurfaceView.getHeight(), gl);

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    bitmapReadyCallbacks.onBitmapReady(snapshotBitmap);
                }
            });

        }
    });

}

// from other answer in this question
private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl) {

    int bitmapBuffer[] = new int[w * h];
    int bitmapSource[] = new int[w * h];
    IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
    intBuffer.position(0);

    try {
        gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);
        int offset1, offset2;
        for (int i = 0; i < h; i++) {
            offset1 = i * w;
            offset2 = (h - i - 1) * w;
            for (int j = 0; j < w; j++) {
                int texturePixel = bitmapBuffer[offset1 + j];
                int blue = (texturePixel >> 16) & 0xff;
                int red = (texturePixel << 16) & 0x00ff0000;
                int pixel = (texturePixel & 0xff00ff00) | red | blue;
                bitmapSource[offset2 + j] = pixel;
            }
        }
    } catch (GLException e) {
        Log.e(TAG, "createBitmapFromGLSurface: " + e.getMessage(), e);
        return null;
    }

    return Bitmap.createBitmap(bitmapSource, w, h, Config.ARGB_8888);
}
19
aaronvargas

注:このコードでは、ボタンをクリックすると、スクリーンショットが画像として取得され、SDカードの場所に保存されます。レンダラークラスがifメソッドをいつでもとにかく呼び出す可能性があるため、ブール条件とonDrawステートメントをonDrawメソッドで使用しました。また、ifがなければ、このコードはメモリカードに多くの画像を保存する可能性があります。

MainActivityクラス:

protected boolean printOptionEnable = false;

saveImageButton.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        Log.v("hari", "pan button clicked");
        isSaveClick = true;
        myRenderer.printOptionEnable = isSaveClick;
    }
});

MyRendererクラス:

int width_surface , height_surface ;

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    Log.i("JO", "onSurfaceChanged");
    // Adjust the viewport based on geometry changes,
    // such as screen rotation
    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    width_surface =  width ;
    height_surface = height ;
}

@Override
public void onDrawFrame(GL10 gl) {
    try {
        if (printOptionEnable) {
            printOptionEnable = false ;
            Log.i("hari", "printOptionEnable if condition:" + printOptionEnable);
            int w = width_surface ;
            int h = height_surface  ;

            Log.i("hari", "w:"+w+"-----h:"+h);

            int b[]=new int[(int) (w*h)];
            int bt[]=new int[(int) (w*h)];
            IntBuffer buffer=IntBuffer.wrap(b);
            buffer.position(0);
            GLES20.glReadPixels(0, 0, w, h,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE, buffer);
            for(int i=0; i<h; i++)
            {
                //remember, that OpenGL bitmap is incompatible with Android bitmap
                //and so, some correction need.        
                for(int j=0; j<w; j++)
                {
                    int pix=b[i*w+j];
                    int pb=(pix>>16)&0xff;
                    int pr=(pix<<16)&0x00ff0000;
                    int pix1=(pix&0xff00ff00) | pr | pb;
                    bt[(h-i-1)*w+j]=pix1;
                }
            }           
            Bitmap inBitmap = null ;
            if (inBitmap == null || !inBitmap.isMutable()
                || inBitmap.getWidth() != w || inBitmap.getHeight() != h) {
                inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            }
            //Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            inBitmap.copyPixelsFromBuffer(buffer);
            //return inBitmap ;
            // return Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
            inBitmap = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);

            ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
            inBitmap.compress(CompressFormat.JPEG, 90, bos); 
            byte[] bitmapdata = bos.toByteArray();
            ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata);

            final Calendar c=Calendar.getInstance();
            long mytimestamp=c.getTimeInMillis();
            String timeStamp=String.valueOf(mytimestamp);
            String myfile="hari"+timeStamp+".jpeg";

            dir_image = new File(Environment.getExternalStorageDirectory()+File.separator+
            "printerscreenshots"+File.separator+"image");
            dir_image.mkdirs();

            try {
                File tmpFile = new File(dir_image,myfile); 
                FileOutputStream fos = new FileOutputStream(tmpFile);

                byte[] buf = new byte[1024];
                int len;
                while ((len = fis.read(buf)) > 0) {
                fos.write(buf, 0, len);
            }
            fis.close();
            fos.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            Log.v("hari", "screenshots:"+dir_image.toString());
        }
    } catch(Exception e) {
        e.printStackTrace();
    }
}
3
harikrishnan

GlsurfaceViewの代わりにTextureViewを拡張したGLTextureViewを使用して、OpenGLデータを表示できます。

参照: http://stackoverflow.com/questions/12061419/converting-from-glsurfaceview-to-textureview-via-gltextureview

GLTextureViewはTextureViewから拡張されているため、機能するgetBitmap関数があります。

myGlTextureView.getBitmap(int width, int height)
0
Andrés