Делая скриншот Android OpenGL - PullRequest
19 голосов
/ 22 июля 2010

Я пытаюсь сделать снимок экрана Android OpenGL.

Код, который я нашел, выглядит следующим образом:

nt size = width * height;
    ByteBuffer buf = ByteBuffer.allocateDirect(size * 4);
    buf.order(ByteOrder.nativeOrder());
    glContext.glReadPixels(0, 0, width, height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, buf);
    int data[] = new int[size];
    buf.asIntBuffer().get(data);
    buf = null;
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    bitmap.setPixels(data, size-width, -width, 0, 0, width, height);
    data = null;

    short sdata[] = new short[size];
    ShortBuffer sbuf = ShortBuffer.wrap(sdata);
    bitmap.copyPixelsToBuffer(sbuf);
    for (int i = 0; i < size; ++i) {
        //BGR-565 to RGB-565
        short v = sdata[i];
        sdata[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11));
    }
    sbuf.rewind();
    bitmap.copyPixelsFromBuffer(sbuf);

    try {
        FileOutputStream fos = new FileOutputStream("/sdcard/screeshot.png");
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
        fos.flush();
        fos.close();
    } catch (Exception e) {
        // handle
    }

Я также попробовал код с этого сайта ссылкатекст

В каждом случае результатом является png-файл, который полностью черный.Я обнаружил, что есть какая-то проблема с glReadPixels методом, но я не знаю, как его обойти.

Ответы [ 3 ]

22 голосов
/ 12 января 2011

Извините за поздний ответ ...

Чтобы сделать правильный скриншот, вы должны поместить в обработчик onDrawFrame (GL10 gl) следующий код:

if(screenshot){                     
                int screenshotSize = width * height;
                ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
                bb.order(ByteOrder.nativeOrder());
                gl.glReadPixels(0, 0, width, height, GL10.GL_RGBA, GL10.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);
                lastScreenshot = bitmap;

                screenshot = false;
            }

Поле класса «снимок экрана» устанавливается в значение «истина», когда пользователь нажимает кнопку, чтобы создать снимок экрана или при любых других обстоятельствах, которые вы хотите. Внутри тела «if» Вы можете поместить любой скриншот, создавая образец кода, который вы найдете в интернете - самое важное - наличие текущего экземпляра GL10. Например, когда вы просто сохраняете экземпляр GL10 в переменную класса, а затем используете его вне события для создания снимка экрана, вы получите полностью пустое изображение. Вот почему вы должны сделать снимок экрана внутри обработчика события OnDrawFrame, где текущий экземпляр GL10. Надеюсь, что это поможет.

С наилучшими пожеланиями, Гордон.

10 голосов
/ 12 августа 2013

Вот способ сделать это, если вы хотите сохранить качество (8 бит для каждого цветового канала: красный, зеленый, синий и альфа):

if (this.screenshot) {
    int screenshotSize = this.width * this.height;
    ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);
    bb.order(ByteOrder.nativeOrder());
    gl.glReadPixels(0, 0, width, height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, bb);
    int pixelsBuffer[] = new int[screenshotSize];
    bb.asIntBuffer().get(pixelsBuffer);
    bb = null;

    for (int i = 0; i < screenshotSize; ++i) {
        // The alpha and green channels' positions are preserved while the red and blue are swapped
        pixelsBuffer[i] = ((pixelsBuffer[i] & 0xff00ff00)) | ((pixelsBuffer[i] & 0x000000ff) << 16) | ((pixelsBuffer[i] & 0x00ff0000) >> 16);
    }

    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    bitmap.setPixels(pixelsBuffer, screenshotSize-width, -width, 0, 0, width, height);
    this.screenshot = false;
}
2 голосов
/ 23 июля 2010

Понял!

Моя ошибка заключалась в том, что я запоминал контекст GL в переменной класса. Чтобы сделать скриншот, я должен использовать контекст gl, переданный OnDraw в классе, реализующем интерфейс GLSurfaceView.Renderer Я просто использую свой код в предложении «если», и все работает как положено. Надеюсь, что это замечание кому-нибудь поможет.

С уважением, Гордон

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...