Java / OpenGL:获取 Canvas 的图像作为 BufferedImage

发布于 2024-12-14 00:03:13 字数 339 浏览 0 评论 0原文

我有一些代码可以初始化 OpenGL 以渲染到 java.awt.Canvas。 问题是,我不知道如何获取画布的缓冲区并将其转换为 BufferedImage。

我尝试过重写 getGraphics()、克隆 Raster 并用自定义的 CanvasPeer 替换 CanvasPeer。

我猜OpenGL不以任何方式使用java图形,那么我怎样才能获取OpenGL的缓冲区并将其转换为BufferedImage?

我正在使用 LWJGL 的代码来设置父级:

Display.setParent(display_parent);
Display.create();

I've got some code that initializes OpenGL to render to a java.awt.Canvas.
The problem is, I can't figure out how I can get the buffer of the canvas and turn it into a BufferedImage.

I've tried overriding getGraphics(), cloning the Raster, and replacing the CanvasPeer with a custom one.

I'm guessing OpenGL doesn't use java graphics in any way then, so how can I get OpenGL's buffer and convert it into a BufferedImage?

I am using LWJGL's code for setting parent:

Display.setParent(display_parent);
Display.create();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小霸王臭丫头 2024-12-21 00:03:13

您需要从 OpenGL 缓冲区复制数据。我正在使用这种方法:

FloatBuffer grabScreen(GL gl) 
{       
    int w = SCREENWITDH;
    int h = SCREENHEIGHT;
    FloatBuffer bufor = FloatBuffer.allocate(w*h*4); // 4 = rgba

    gl.glReadBuffer(GL.GL_FRONT);
    gl.glReadPixels(0, 0, w, h, GL.GL_RGBA, GL.GL_FLOAT, bufor); //Copy the image to the array imageData

    return bufor;
}

您需要根据您的 OpenGL 包装器使用类似的方法。这是 JOGL 示例。

这里是 LWJGL 包装器:

private static synchronized byte[] grabScreen()
{
    int w = screenWidth;
    int h = screenHeight;
    ByteBuffer bufor = BufferUtils.createByteBuffer(w * h * 3);

    GL11.glReadPixels(0, 0, w, h, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, bufor); //Copy the image to the array imageData

    byte[] byteimg = new byte[w * h * 3];
    bufor.get(byteimg, 0, byteimg.length);
    return byteimg;
}

编辑

这也可能有用(它不完全是我的,也应该调整):

BufferedImage toImage(byte[] data, int w, int h)
{
    if (data.length == 0)
        return null;

    DataBuffer buffer = new DataBufferByte(data, w * h);

    int pixelStride = 3; //assuming r, g, b, skip, r, g, b, skip...
    int scanlineStride = 3 * w; //no extra padding   
    int[] bandOffsets = { 0, 1, 2 }; //r, g, b
    WritableRaster raster = Raster.createInterleavedRaster(buffer, w, h, scanlineStride, pixelStride, bandOffsets,
            null);

    ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
    boolean hasAlpha = false;
    boolean isAlphaPremultiplied = true;
    int transparency = Transparency.TRANSLUCENT;
    int transferType = DataBuffer.TYPE_BYTE;
    ColorModel colorModel = new ComponentColorModel(colorSpace, hasAlpha, isAlphaPremultiplied, transparency,
            transferType);

    BufferedImage image = new BufferedImage(colorModel, raster, isAlphaPremultiplied, null);

    AffineTransform flip;
    AffineTransformOp op;
    flip = AffineTransform.getScaleInstance(1, -1);
    flip.translate(0, -image.getHeight());
    op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
    image = op.filter(image, null);

    return image;
}

You need to copy data from OpenGL buffer. I was using this method:

FloatBuffer grabScreen(GL gl) 
{       
    int w = SCREENWITDH;
    int h = SCREENHEIGHT;
    FloatBuffer bufor = FloatBuffer.allocate(w*h*4); // 4 = rgba

    gl.glReadBuffer(GL.GL_FRONT);
    gl.glReadPixels(0, 0, w, h, GL.GL_RGBA, GL.GL_FLOAT, bufor); //Copy the image to the array imageData

    return bufor;
}

You need to use something similar according to your OpenGL wrapper. This is JOGL example.

And here for LWJGL wrapper:

private static synchronized byte[] grabScreen()
{
    int w = screenWidth;
    int h = screenHeight;
    ByteBuffer bufor = BufferUtils.createByteBuffer(w * h * 3);

    GL11.glReadPixels(0, 0, w, h, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, bufor); //Copy the image to the array imageData

    byte[] byteimg = new byte[w * h * 3];
    bufor.get(byteimg, 0, byteimg.length);
    return byteimg;
}

EDIT

This may be useful also (it's not fully mine, should be tuned too):

BufferedImage toImage(byte[] data, int w, int h)
{
    if (data.length == 0)
        return null;

    DataBuffer buffer = new DataBufferByte(data, w * h);

    int pixelStride = 3; //assuming r, g, b, skip, r, g, b, skip...
    int scanlineStride = 3 * w; //no extra padding   
    int[] bandOffsets = { 0, 1, 2 }; //r, g, b
    WritableRaster raster = Raster.createInterleavedRaster(buffer, w, h, scanlineStride, pixelStride, bandOffsets,
            null);

    ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
    boolean hasAlpha = false;
    boolean isAlphaPremultiplied = true;
    int transparency = Transparency.TRANSLUCENT;
    int transferType = DataBuffer.TYPE_BYTE;
    ColorModel colorModel = new ComponentColorModel(colorSpace, hasAlpha, isAlphaPremultiplied, transparency,
            transferType);

    BufferedImage image = new BufferedImage(colorModel, raster, isAlphaPremultiplied, null);

    AffineTransform flip;
    AffineTransformOp op;
    flip = AffineTransform.getScaleInstance(1, -1);
    flip.translate(0, -image.getHeight());
    op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
    image = op.filter(image, null);

    return image;
}
生生不灭 2024-12-21 00:03:13

我认为这对于您的情况来说是不可能的,原因如下:

LWJGL 不会直接绘制到画布上(至少在 Windows 中不会)。画布仅用于获取窗口句柄以作为父窗口提供给 OpenGL。因此,画布永远不会被直接绘制。要捕获内容,您可能必须求助于屏幕捕获。

I don't think this is possible for your situation, and here's why:

LWJGL doesn't draw directly to the canvas (at least not in Windows). The canvas is only used to obtain a window handle to provide as the parent window to OpenGL. As such, the canvas is never directly drawn to. To capture the contents, you'll probably have to resort to a screen capture.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文