5
$\begingroup$

I have got a texture ID and would like to retrieve its data. The data should be stored in a BufferedImage for future use. I am using the LWJGL library in Java, so if there are some library-specific shortcuts I'd like to use them.

My naive approach is to first fill a buffer with the image data and then pass it to the image.

int id = ...;
IntBuffer buff = BufferUtils.createIntBuffer(1024*512*4);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, id);
System.out.println(buff.remaining());
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buff);
System.out.println(buff.remaining());
buff.flip();
buff.rewind();
System.out.println(buff.remaining());
// Somehow create a BufferedImage from buff here

I don't know why, but the first and to buff.remaining() return the same value, indicating that nothing has been written which should not be the case.

$\endgroup$

1 Answer 1

5
$\begingroup$

To make it a more complete example, let's also consider loading a texture from a BufferedImage as well.

First let's assume:

int texture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, texture);

First we need to load an image. For this we can use ImageIO.read(). Then we put all the pixels from the BufferedImage into a ByteBuffer.

BufferedImage image = ImageIO.read(new File("image.png"));
int width = image.getWidth(), height = image.getHeight();

int[] pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);

ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4); // 4 because RGBA

for(int y = 0; y < height; ++y) {
    for(int x = 0; x < width; ++x) {
        int pixel = pixels[x + y * width];
        buffer.put((byte) ((pixel >> 16) & 0xFF));
        buffer.put((byte) ((pixel >> 8) & 0xFF));
        buffer.put((byte) (pixel & 0xFF));
        buffer.put((byte) ((pixel >> 24) & 0xFF));
    }
}

buffer.flip();

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

Before we go ahead and call glGetTexImage() lets assume that the only thing we have is the texture name (texture). Thus we consider that we don't know the size or format of the texture. We can get all this by doing:

int format = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT);
int width = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH);
int height = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT);

Using that information we again create a ByteBuffer as well as a BufferedImage. Reading the pixels from the ByteBuffer and placing them on the BufferedImage.

int channels = 4;
if (format == GL_RGB)
    channels = 3;

ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * channels);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, buffer);

for (int x = 0; x < width; ++x) {
    for (int y = 0; y < height; ++y) {
        int i = (x + y * width) * channels;

        int r = buffer.get(i) & 0xFF;
        int g = buffer.get(i + 1) & 0xFF;
        int b = buffer.get(i + 2) & 0xFF;
        int a = 255;
        if (channels == 4)
            a = buffer.get(i + 3) & 0xFF;

        image.setRGB(x, y, (a << 24) | (r << 16) | (g << 8) | b);
    }
}

Now go ahead and save that BufferedImage to a file.

ImageIO.write(image, "PNG", new File("out.png"));

Last but not least, you can get rid of all those GL11. prefixes, by statically importing GL11. You do that by doing:

import static org.lwjgl.opengl.GL11.*;
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.