2010-07-22 3 views
19

Я пытаюсь сделать снимок экрана Android OpenGL.Снимок экрана 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 
    } 

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

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

ответ

2

Понял!

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

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

22

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

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

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

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

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

+0

я получаю erroneal цвета с этим например, желтые цвета окрашены в синий цвет ... ¿? как его решить, пожалуйста? – NullPointerException

+0

@ Gordon Как вы инициализируете gl? – XXX

10

Вот способ сделать это, если вы хотите сохранить качество (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; 
} 
+0

Большое спасибо, это спасло мою долгую лелею ....: P @Spartarel –

+0

Я использовал ваш метод, и он отлично работает, если я сохраню растровое изображение за 1 секунду, сделав значение скриншота истинным. если я даже дождался 500 milisec, это сэкономит плохое цветное изображение ... это операция занимает больше времени? @Spatarel –

+0

@Hissain вы когда-нибудь находили решение этой проблемы? – anakin78z