Снимок экрана 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
}
Я попробовал также код из этого сайта ссылку на текст
В каждом случае результатом является файл PNG, который полностью черный. Я обнаружил, что есть некоторая проблема с glReadPixels
метод, но я не знаю, как это обойти.
3 ответа
Извините за поздний ответ...
Чтобы сделать правильный снимок экрана, вы должны поместить в обработчик 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. Надеюсь, что это поможет.
С наилучшими пожеланиями, Гордон.
Вот способ сделать это, если вы хотите сохранить качество (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;
}
Понял!
Моя ошибка заключалась в том, что я запоминал контекст GL в переменной класса. Чтобы сделать снимок экрана, я должен использовать контекст gl, переданный OnDraw в классе, реализующем интерфейс GLSurfaceView.Renderer. Я просто использую свой код в предложении if, и все работает как положено. Надеюсь, что это замечание поможет кому-нибудь.
С наилучшими пожеланиями, Гордон