package org.andengine.entity.util; import java.nio.IntBuffer; import org.andengine.engine.camera.Camera; import org.andengine.entity.Entity; import org.andengine.opengl.util.GLState; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.opengl.GLES20; /** * (c) 2010 Nicolas Gramlich * (c) 2011 Zynga Inc. * * @author Nicolas Gramlich * @since 15:27:22 - 10.01.2011 */ public class ScreenGrabber extends Entity { // =========================================================== // Constants // =========================================================== // =========================================================== // Fields // =========================================================== private int mGrabX; private int mGrabY; private int mGrabWidth; private int mGrabHeight; private boolean mScreenGrabPending = false; private IScreenGrabberCallback mScreenGrabCallback; // =========================================================== // Constructors // =========================================================== // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== @Override protected void onManagedDraw(final GLState pGLState, final Camera pCamera) { if(this.mScreenGrabPending) { try { final Bitmap screenGrab = ScreenGrabber.grab(this.mGrabX, this.mGrabY, this.mGrabWidth, this.mGrabHeight); this.mScreenGrabCallback.onScreenGrabbed(screenGrab); } catch (final Exception e) { this.mScreenGrabCallback.onScreenGrabFailed(e); } this.mScreenGrabPending = false; } } @Override protected void onManagedUpdate(final float pSecondsElapsed) { /* Nothing */ } @Override public void reset() { /* Nothing */ } // =========================================================== // Methods // =========================================================== public void grab(final int pGrabWidth, final int pGrabHeight, final IScreenGrabberCallback pScreenGrabCallback) { this.grab(0, 0, pGrabWidth, pGrabHeight, pScreenGrabCallback); } public void grab(final int pGrabX, final int pGrabY, final int pGrabWidth, final int pGrabHeight, final IScreenGrabberCallback pScreenGrabCallback) { this.mGrabX = pGrabX; this.mGrabY = pGrabY; this.mGrabWidth = pGrabWidth; this.mGrabHeight = pGrabHeight; this.mScreenGrabCallback = pScreenGrabCallback; this.mScreenGrabPending = true; } private static Bitmap grab(final int pGrabX, final int pGrabY, final int pGrabWidth, final int pGrabHeight) { final int[] source = new int[pGrabWidth * (pGrabY + pGrabHeight)]; final IntBuffer sourceBuffer = IntBuffer.wrap(source); sourceBuffer.position(0); // TODO Check availability of OpenGL and GLES20.GL_RGBA combinations that require less conversion operations. // Note: There is (said to be) a bug with glReadPixels when 'y != 0', so we simply read starting from 'y == 0'. // TODO Does that bug still exist? GLES20.glReadPixels(pGrabX, 0, pGrabWidth, pGrabY + pGrabHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, sourceBuffer); final int[] pixels = new int[pGrabWidth * pGrabHeight]; // Convert from RGBA_8888 (Which is actually ABGR as the whole buffer seems to be inverted) --> ARGB_8888 for (int y = 0; y < pGrabHeight; y++) { for (int x = 0; x < pGrabWidth; x++) { final int pixel = source[x + ((pGrabY + y) * pGrabWidth)]; final int blue = (pixel & 0x00FF0000) >> 16; final int red = (pixel & 0x000000FF) << 16; final int greenAlpha = pixel & 0xFF00FF00; pixels[x + ((pGrabHeight - y - 1) * pGrabWidth)] = greenAlpha | red | blue; } } return Bitmap.createBitmap(pixels, pGrabWidth, pGrabHeight, Config.ARGB_8888); } // =========================================================== // Inner and Anonymous Classes // =========================================================== public static interface IScreenGrabberCallback { // =========================================================== // Constants // =========================================================== // =========================================================== // Methods // =========================================================== public void onScreenGrabbed(final Bitmap pBitmap); public void onScreenGrabFailed(final Exception pException); } }