Efficiently extracting RGBA buffer from BufferedImage

我是研究僧i 提交于 2021-02-11 17:19:32

问题


I've been trying to load in bufferedImages in java as IntBuffers. However, one problem I've come across is getting the pixel data from an image with semi or complete transparency. Java only seems to allow you to get the RGB value, which in my case is a problem because any pixels that should be transparent are rendered completely opaque. After about a few hours of searching I came across this way of getting the RGBA values...

Color color = new Color(image.getRGB(x, y), true);

Although it does work, it can't possibly be the best way of doing this. Does anyone know of a more efficient way to complete the same task, one that does not require an instance of a color object for EVERY pixel. You can see how this would be bad if you're trying to load in a fairly large image. Here is my code just in case you need a reference...

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;

}

*Edit: The bufferedImage passed into the parameter is loaded from the disk


回答1:


Here's some old code I have that converts images to OpenGL for LWJGL. Since the byte order has to be swapped, it isn't useful (I think) to load the image as for example integers.

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

Example usage:

    BufferedImage image = ImageIO.read( getClass().getResourceAsStream(heightMapFile) );

    int height = image.getHeight();
    int width = image.getWidth();
    ByteBuffer buf = TextureUtils.decodePng(image);



回答2:


If interested, I did a jvm port of gli that deals with these stuff so that you don't have to worry about.

An example of texture loading:

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


来源:https://stackoverflow.com/questions/48875161/efficiently-extracting-rgba-buffer-from-bufferedimage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!