Capture screen of GLSurfaceView to bitmap

glsurfaceview example
android glsurfaceview tutorial
gltextureview android
android opengl set background image
onsurfacecreated android
glview android
convert surfaceview to textureview
gpu imageview in android

I need to be able to capture an image of a GLSurfaceView at certain moment in time. I have the following code:

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

The GLSurfaceView is contained within a RelativeLayout, but I have also tries it straight using the GLSurfaceView to try and capture the image. With this I think the screen captures a transparent image, i.e. nothing there. Any help will be appreciated.


SurfaceView and GLSurfaceView punch holes in their windows to allow their surfaces to be displayed. In other words, they have transparent areas.

So you cannot capture an image by calling GLSurfaceView.getDrawingCache().

If you want to get an image from GLSurfaceView, you should invoke gl.glReadPixels() in GLSurfaceView.onDrawFrame().

I patched createBitmapFromGLSurface method and call it in onDrawFrame().

(The original code might be from skuld's code.)

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

Take a screenshot of the GLSurfaceView as bitmap · Issue #8 , If you have inmersive feature In your android (versions >=4.4) you can use android's own screen capture feature to capture a full snapshot of the  So you cannot capture an image by calling GLSurfaceView.getDrawingCache(). If you want to get an image from GLSurfaceView , you should invoke gl.glReadPixels() in GLSurfaceView.onDrawFrame() . I patched createBitmapFromGLSurface method and call it in onDrawFrame() .


Here is a complete solution if you are using a third party library that you just 'pass in' a GLSurfaceView defined in your layout. You won't have a handle on the onDrawFrame() of the renderer, this can be a problem...

To do this you need to queue it up for the GLSurfaceView to handle.

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

Capture screen of GLSurfaceView to bitmap, Capture screen of GLSurfaceView to bitmap, Programmer Sought, the best private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl) throws  So you cannot capture an image by calling GLSurfaceView.getDrawingCache(). If you want to get an image from GLSurfaceView, you should invoke gl.glReadPixels() in GLSurfaceView.onDrawFrame(). I patched createBitmapFromGLSurface method and call it in onDrawFrame().


Note: In this code, when I click the Button, it takes the screenshot as Image and saves it in sdcard location. I used boolean condition and an if statement in onDraw method, because the renderer class may call the onDraw method anytime and anyway, and without the if this code may save lots of images in the memory card.

MainActivity class:

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 class:

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

javax.microedition.khronos.opengles.GL10.glReadPixels java code , Extract the bitmap from OpenGL * * @param x the start column * @param y the start line * @param w the width of Capture screen of GLSurfaceView to bitmap. Take a screenshot of the GLSurfaceView as bitmap #8. Open you can use android's own screen capture feature to capture a full snapshot of the screen.


You can use a GLTextureView extending TextureView instead of GlsurfaceView to show you OpenGL data.

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

As the GLTextureView extends from TextureView, it has a getBitmap function that should work.

myGlTextureView.getBitmap(int width, int height)

Android: Saving Screenshots in OpenGLES - MM, public static void saveBitmap(@NotNull Bitmap screenshot, @NotNull String filePath, @NotNull String public Bitmap captureScreenShot() { //Making created bitmap (from OpenGL points) compatible with Android bitmap. le GLSurfaceView est contenu dans un RelativeLayout, mais je l'ai aussi essayé directement en utilisant le GLSurfaceView pour essayer de capturer l'image. Avec cela je pense que l'écran capture une image transparente, i.e. rien là. Toute aide sera appréciée.


How to save an image after applying an effect (filter) to it , I tried it by taking the screenshot of the rendered view but I know that there is some other way out. Intent; import android.graphics.Bitmap; import android.​graphics. private GLSurfaceView mEffectView; private int[] mTextures = new int[​2]; ACTION_IMAGE_CAPTURE); startActivityForResult(intent, 0);  Capture screen of GLSurfaceView to bitmap (3) SurfaceView and GLSurfaceView punch holes in their windows to allow their surfaces to be displayed. In other words, they have transparent areas.


Hi, I have written my Android app (java) so it can capture my Android app screen (framebuffer) put it in a bitmap then run a filter on the bitmap then put it back into a resultant bitmap to display as a texture overlay. I am using glreadpixels for opengl es 3.0 to get the image.


I want to display a bitmap image at screen using texture api in android opengl. Some code which I have used in our code as below. public void onSurfaceChanged(GL10 gl, int width, int height) {