user2212391
user2212391

Reputation: 71

Capture rendered image from OpenGL in Android and save it to a JPEG

I have a problem with saving a rendered image to my gallery as a jpeg file. I'm applying a photo effect from the android EffectFactory an render it on a glSurfaceView. Since now i#ve managed to take a screenshot of the image from my glSurfaceView. The problem is that i don't want to take just a screenshot because then the image looses much of its original size and quality because when the original image is e.g. 1944 × 2592 but the device screen is only 768 × 1038 in my case its not the original anymore. The other problem is that when i take a screenshot i have also the black parts of my glSurfacView where the image isn't displayed on my saved image because the image doens't fill the whole glSurfaceView in many cases. Since now i tried it with this 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);
}

Can anyone please tell me how i get a bitmap/jpeg from the rendered image in the original size of the image? Is it even possible with gl.glReadPixels?? Or can i get the image directly from a framebuffer somehow? Its important that i can get the image in its original size.

Upvotes: 4

Views: 2172

Answers (2)

Mohamed Rahal
Mohamed Rahal

Reputation: 73

To solve the problem, another method can be used to obtain the image. Instead of using glReadPixels, you can use the PixelCopy method to copy the image from the view.

Here's how to use PixelCopy:

public void takeScreenshot(SurfaceView view) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
    PixelCopy.request(view, bitmap, new PixelCopy.OnPixelCopyFinishedListener() {
        @Override
        public void onPixelCopyFinished(int copyResult) {
            if (copyResult == PixelCopy.SUCCESS) {
            // Do something with the bitmap, e.g., save it to a file or display it in an ImageView
            } else {
            // Handle the error, e.g., show a toast with an error message
            }
        }
    }, new Handler());
}

Don't forget to add the declaration in the AndroidManifest.xml file to enable the use of PixelCopy:

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

Upvotes: 0

AndroidLad
AndroidLad

Reputation: 697

    public static Bitmap createBitmap(int width,int height){

//			int width=bitmap.getWidth();
//			int height =bitmap.getHeight();
            int screenshotSize = width * height;
            ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
            bb.order(ByteOrder.nativeOrder());
            GLES20.glReadPixels(5, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, bb);
            int pixelsBuffer[] = new int[screenshotSize];
            bb.asIntBuffer().get(pixelsBuffer);
            bb = null;
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
            bitmap.setPixels(pixelsBuffer, screenshotSize-width, -width,0, 0, width, height);
            pixelsBuffer = null;

            short sBuffer[] = new short[screenshotSize];
            ShortBuffer sb = ShortBuffer.wrap(sBuffer);
            bitmap.copyPixelsToBuffer(sb);

            //Making created bitmap (from OpenGL points) compatible with Android bitmap
            for (int i = 0; i < screenshotSize; ++i) {
                short v = sBuffer[i];
                sBuffer[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11));
            }
            sb.rewind();
            bitmap.copyPixelsFromBuffer(sb);
//            if(savepicture!=null){
//                savepicture.onPictureSaved(bitmap);
//                // new SaveTask(bitmap, FileUtils.getFileDir().getPath(),"IMG"+System.currentTimeMillis()+".png", savepicture).execute();
//                screenshot = false;
//            }

            return bitmap;
    }

Upvotes: 2

Related Questions