从 BufferedImage 中高效提取 RGBA 缓冲区
Efficiently extracting RGBA buffer from BufferedImage
我一直在尝试将 java 中的 bufferedImages 作为 IntBuffers 加载。但是,我遇到的一个问题是从半透明或完全透明的图像中获取像素数据。 Java 似乎只允许您获取 RGB 值,这在我的例子中是个问题,因为任何应该透明的像素都呈现为完全不透明。经过大约几个小时的搜索,我发现了这种获取 RGBA 值的方法...
Color color = new Color(image.getRGB(x, y), true);
虽然它确实有效,但它可能不是执行此操作的最佳方法。有谁知道完成相同任务的更有效方法,不需要每个像素的颜色对象实例。如果您尝试加载相当大的图像,您会发现这有多么糟糕。这是我的代码,以防您需要参考...
public static IntBuffer getImageBuffer(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
for (int i = 0; i < pixels.length; i++) {
Color color = new Color(image.getRGB(i % width, i / width), true);
int a = color.getAlpha();
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
pixels[i] = a << 24 | b << 16 | g << 8 | r;
}
return BufferUtils.toIntBuffer(pixels);
}
public static IntBuffer toIntBuffer(int[] elements) {
IntBuffer buffer = ByteBuffer.allocateDirect(elements.length << 2).order(ByteOrder.nativeOrder()).asIntBuffer();
buffer.put(elements).flip();
return buffer;
}
*编辑:传入参数的bufferedImage是从磁盘加载的
这是我的一些旧代码,可将图像转换为适用于 LWJGL 的 OpenGL。由于必须交换字节顺序,因此(我认为)将图像加载为整数没有用。
public static ByteBuffer decodePng( BufferedImage image )
throws IOException
{
int width = image.getWidth();
int height = image.getHeight();
// Load texture contents into a byte buffer
ByteBuffer buf = ByteBuffer.allocateDirect( 4 * width * height );
// decode image
// ARGB format to -> RGBA
for( int h = 0; h < height; h++ )
for( int w = 0; w < width; w++ ) {
int argb = image.getRGB( w, h );
buf.put( (byte) ( 0xFF & ( argb >> 16 ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 8 ) ) );
buf.put( (byte) ( 0xFF & ( argb ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 24 ) ) );
}
buf.flip();
return buf;
}
用法示例:
BufferedImage image = ImageIO.read( getClass().getResourceAsStream(heightMapFile) );
int height = image.getHeight();
int width = image.getWidth();
ByteBuffer buf = TextureUtils.decodePng(image);
如果有兴趣,我做了一个 jvm port of gli
来处理这些东西,这样你就不用担心了。
纹理加载示例:
public static int createTexture(String filename) {
Texture texture = gli.load(filename);
if (texture.empty())
return 0;
gli_.gli.gl.setProfile(gl.Profile.GL33);
gl.Format format = gli_.gli.gl.translate(texture.getFormat(), texture.getSwizzles());
gl.Target target = gli_.gli.gl.translate(texture.getTarget());
assert (texture.getFormat().isCompressed() && target == gl.Target._2D);
IntBuffer textureName = intBufferBig(1);
glGenTextures(textureName);
glBindTexture(target.getI(), textureName.get(0));
glTexParameteri(target.getI(), GL12.GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target.getI(), GL12.GL_TEXTURE_MAX_LEVEL, texture.levels() - 1);
IntBuffer swizzles = intBufferBig(4);
texture.getSwizzles().to(swizzles);
glTexParameteriv(target.getI(), GL33.GL_TEXTURE_SWIZZLE_RGBA, swizzles);
Vec3i extent = texture.extent(0);
glTexStorage2D(target.getI(), texture.levels(), format.getInternal().getI(), extent.x, extent.y);
for (int level = 0; level < texture.levels(); level++) {
extent = texture.extent(level);
glCompressedTexSubImage2D(
target.getI(), level, 0, 0, extent.x, extent.y,
format.getInternal().getI(), texture.data(0, 0, level));
}
return textureName.get(0);
}
我一直在尝试将 java 中的 bufferedImages 作为 IntBuffers 加载。但是,我遇到的一个问题是从半透明或完全透明的图像中获取像素数据。 Java 似乎只允许您获取 RGB 值,这在我的例子中是个问题,因为任何应该透明的像素都呈现为完全不透明。经过大约几个小时的搜索,我发现了这种获取 RGBA 值的方法...
Color color = new Color(image.getRGB(x, y), true);
虽然它确实有效,但它可能不是执行此操作的最佳方法。有谁知道完成相同任务的更有效方法,不需要每个像素的颜色对象实例。如果您尝试加载相当大的图像,您会发现这有多么糟糕。这是我的代码,以防您需要参考...
public static IntBuffer getImageBuffer(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
for (int i = 0; i < pixels.length; i++) {
Color color = new Color(image.getRGB(i % width, i / width), true);
int a = color.getAlpha();
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
pixels[i] = a << 24 | b << 16 | g << 8 | r;
}
return BufferUtils.toIntBuffer(pixels);
}
public static IntBuffer toIntBuffer(int[] elements) {
IntBuffer buffer = ByteBuffer.allocateDirect(elements.length << 2).order(ByteOrder.nativeOrder()).asIntBuffer();
buffer.put(elements).flip();
return buffer;
}
*编辑:传入参数的bufferedImage是从磁盘加载的
这是我的一些旧代码,可将图像转换为适用于 LWJGL 的 OpenGL。由于必须交换字节顺序,因此(我认为)将图像加载为整数没有用。
public static ByteBuffer decodePng( BufferedImage image )
throws IOException
{
int width = image.getWidth();
int height = image.getHeight();
// Load texture contents into a byte buffer
ByteBuffer buf = ByteBuffer.allocateDirect( 4 * width * height );
// decode image
// ARGB format to -> RGBA
for( int h = 0; h < height; h++ )
for( int w = 0; w < width; w++ ) {
int argb = image.getRGB( w, h );
buf.put( (byte) ( 0xFF & ( argb >> 16 ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 8 ) ) );
buf.put( (byte) ( 0xFF & ( argb ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 24 ) ) );
}
buf.flip();
return buf;
}
用法示例:
BufferedImage image = ImageIO.read( getClass().getResourceAsStream(heightMapFile) );
int height = image.getHeight();
int width = image.getWidth();
ByteBuffer buf = TextureUtils.decodePng(image);
如果有兴趣,我做了一个 jvm port of gli
来处理这些东西,这样你就不用担心了。
纹理加载示例:
public static int createTexture(String filename) {
Texture texture = gli.load(filename);
if (texture.empty())
return 0;
gli_.gli.gl.setProfile(gl.Profile.GL33);
gl.Format format = gli_.gli.gl.translate(texture.getFormat(), texture.getSwizzles());
gl.Target target = gli_.gli.gl.translate(texture.getTarget());
assert (texture.getFormat().isCompressed() && target == gl.Target._2D);
IntBuffer textureName = intBufferBig(1);
glGenTextures(textureName);
glBindTexture(target.getI(), textureName.get(0));
glTexParameteri(target.getI(), GL12.GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target.getI(), GL12.GL_TEXTURE_MAX_LEVEL, texture.levels() - 1);
IntBuffer swizzles = intBufferBig(4);
texture.getSwizzles().to(swizzles);
glTexParameteriv(target.getI(), GL33.GL_TEXTURE_SWIZZLE_RGBA, swizzles);
Vec3i extent = texture.extent(0);
glTexStorage2D(target.getI(), texture.levels(), format.getInternal().getI(), extent.x, extent.y);
for (int level = 0; level < texture.levels(); level++) {
extent = texture.extent(level);
glCompressedTexSubImage2D(
target.getI(), level, 0, 0, extent.x, extent.y,
format.getInternal().getI(), texture.data(0, 0, level));
}
return textureName.get(0);
}