代码之家  ›  专栏  ›  技术社区  ›  Spice

从BuffereImage中高效提取RGBA缓冲区

  •  0
  • Spice  · 技术社区  · 6 年前

    我一直在尝试将java中的BuffereImage加载为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;
    
    }
    

    *编辑:传入参数的BuffereImage从磁盘加载

    2 回复  |  直到 6 年前
        1
  •  2
  •   markspace    6 年前

    这里有一些将图像转换为OpenGL for LWJGL的旧代码。由于必须交换字节顺序,因此(我认为)以整数为例加载图像是没有用的。

       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);
    
        2
  •  1
  •   elect    6 年前

    如果有兴趣,我会 jvm port 属于 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);
    }