【问题标题】:Efficiently extracting RGBA buffer from BufferedImage从 BufferedImage 中高效提取 RGBA 缓冲区
【发布时间】:2018-02-22 07:44:51
【问题描述】:

我一直在尝试将 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是从磁盘加载的

【问题讨论】:

  • 那么你到底想做什么?您是从磁盘或网络加载图像,还是自己制作?
  • getRGB 返回的值不是已经是打包的int 值了吗?为什么需要转换它? (是的,它包括 alpha,否则 Color(int, boolean) 将无法工作......)
  • 我转换它的原因是因为我使用的是 OpenGL,它将像素数据读取为 ABGR 而不是 RGBA。
  • 我也在从磁盘加载图像
  • 从磁盘加载的最快方法是使用大的直接字节缓冲区。如果您正在加载实际图像(jpeg、png),在图像数据之前会有一个标题,并且尝试使用 IntBuffer 或其他东西将无法正常工作。

标签: java bufferedimage


【解决方案1】:

这是我的一些旧代码,用于将图像转换为 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);

【讨论】:

    【解决方案2】:

    如果有兴趣,我做了一个glijvm port 来处理这些东西,这样你就不必担心了。

    纹理加载示例:

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

    【讨论】:

      最近更新 更多