public class

ScreenGrabber

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