在 Android OpenGL ES 中将 2D 纹理保存为 png

Posted

技术标签:

【中文标题】在 Android OpenGL ES 中将 2D 纹理保存为 png【英文标题】:Save 2D texture to a png in Android OpenGL ES 【发布时间】:2012-11-14 10:10:10 【问题描述】:

我是 androidOpenGL ES 的新手。但是现在,我需要使用OpenGL ES 2.0 进行一些照片编辑。我在 Android 4.1.2 中找到了示例代码"Hello-effect",它完成了编辑照片并将其渲染到窗口的工作。但现在,我还需要将编辑后的照片保存到本地位图。我认为可能有一些方法可以直接从纹理中获取数据,但我发现的唯一方法是glReadPixels(...)。所以我做了一些尝试使用它:

我做的第一个测试:

    我使用 GLSurfaceView 来显示经过 android.media.effect API 编辑的照片。 我在包含 GLSurfaceView 的相同布局中添加了一个按钮。 单击按钮时,我调用 glReadPixels(...) 来获取照片数据。 但作为第 3 步,我只得到了 botton 的数据。
我猜当我单击按钮时,窗口的帧缓冲区已被按钮的内容替换。

我做的第二个测试:

    我创建了一个 FBO 来保存编辑过的照片并使用 glReadPixels(...) 来获取照片数据,但它是一张黑色图片。

代码如下:

public void renderTextureOffscreen (int texId) 
    // Bind default FBO
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, offScreenFrameBuffer[0]); 
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,GLES20.GL_COLOR_ATTACHMENT0,GLES20.GL_TEXTURE_2D, texId , 0);

    int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
    if(status == GLES20.GL_FRAMEBUFFER_COMPLETE)
    
        // Set viewport
        GLES20.glViewport(0, 0, mViewWidth, mViewHeight);
        GLToolbox.checkGlError("glViewport");

        // Disable blending
        GLES20.glDisable(GLES20.GL_BLEND);

        // Set the vertex attributes
        GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false,
            0, mTexVertices);
        GLES20.glEnableVertexAttribArray(mTexCoordHandle);
        GLES20.glVertexAttribPointer(mPosCoordHandle, 2, GLES20.GL_FLOAT, false,
            0, mPosVertices);
        GLES20.glEnableVertexAttribArray(mPosCoordHandle);
        GLToolbox.checkGlError("vertex attribute setup");

        // Set the input texture
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLToolbox.checkGlError("glActiveTexture");
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
        GLToolbox.checkGlError("glBindTexture");
        GLES20.glUniform1i(mTexSamplerHandle, 0);

        // Draw
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    

我的问题是我的猜测是否正确?而作为 FBO 方法,我是否会失去完成工作的关键步骤。

【问题讨论】:

【参考方案1】:

尝试在之后立即读取像素

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 

还要确保从正确的线程调用 glReadPixels,即在您的渲染器子类中。

还有一件事,我看到你将用于 FBO 的纹理绑定为着色器的输入,你不能这样做。

我想在 RTT 之后,您将结果渲染到四边形或屏幕上的其他东西,对吗?

你能展示你用来读取像素的其余代码吗?

【讨论】:

以上是关于在 Android OpenGL ES 中将 2D 纹理保存为 png的主要内容,如果未能解决你的问题,请参考以下文章

Android - 使用 openGL ES 绘制 3D 然后 2D

Android OpenGL ES:展示一张2d图片

Android OpenGL ES:展示一张2d图片

如何在 Android 中将 OpenCV 旋转和平移矢量与 OpenGL ES 一起使用?

使用 OpenGL ES 2.0 绘制 2D 图像

对象边缘的Android Opengl ES暗像素