简体   繁体   English

截取Android OpenGL的截图

[英]Taking screenshot of Android OpenGL

I'm trying to take a screenshot of Android OpenGL. 我正在尝试截取Android OpenGL的截图。

The code I found is as follows: 我找到的代码如下:

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
    }

I tried also a code from that site link text 我还尝试了该站点链接文本中的代码

In each case the result is a png file which is completely black. 在每种情况下,结果都是一个完全黑色的png文件。 I found there is some problem with glReadPixels method but I don't know how to bypass it. 我发现glReadPixels方法存在一些问题,但我不知道如何绕过它。

Sorry for the late response... 回复晚了非常抱歉...

In order to perform a correct screenshot You have to put into Your onDrawFrame(GL10 gl) handler the following code: 为了执行正确的屏幕截图您必须将以下代码放入您的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;
            }

The "screenshot" class field is set to true whenever the user presses the button to create a screenshot or at any other circumstances You want. 只要用户按下按钮创建屏幕截图或您想要的任何其他情况,“screenshot”类字段就会设置为true。 Inside the "if" body You may place any screenshot creating code sample You find in th internet - the most important thing is having the current instance of GL10. 在“if”主体内你可以放置任何截图创建代码样本你在互联网上找到 - 最重要的是拥有GL10的当前实例。 For example when You just save the GL10 instance to the class variable and then use it outside the event to create the screenshot You'll end up with the completely blank image. 例如,当您只是将GL10实例保存到类变量然后在事件外使用它来创建屏幕截图您将最终得到完全空白的图像。 That's why You have to take a screenshot inside the OnDrawFrame event handler where the GL10 instance is the current one. 这就是为什么你必须在OnDrawFrame事件处理程序中截取GL10实例是当前实例的截图。 Hope that it helps. 希望它有所帮助。

Best regards, Gordon. 最好的问候,戈登。

Here is the way to do it if you want to preserve the quality (8 bits for every colour channel: red, green, blue and alpha too): 如果你想保持质量(每个颜色通道8位:红色,绿色,蓝色和alpha),下面是这样做的方法:

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

Got it! 得到它了!

My mistake was that I was remembering GL context in the class variable. 我的错误是我在类变量中记住GL上下文。 In order to take a screenshot I have to use the gl context passed to the OnDraw in the class implementing GLSurfaceView.Renderer interface. 为了拍摄截图,我必须使用传递给实现GLSurfaceView.Renderer接口的类中的OnDraw的gl上下文。 I simply use my code in the "if" clause and everything works as expected. 我只是在“if”子句中使用我的代码,一切都按预期工作。 Hope that remark would help anyone. 希望这句话可以帮助任何人。

Best regards, Gordon 最好的问候,戈登

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM