将原始像素数据(作为字节数组)转换为 BufferedImage

Convert raw pixel data (as byte array) to BufferedImage

我需要使用一个本地库来读取一些专有图像文件格式(关于不重新发明我们自己的轮子)。该库运行良好,只是有时图像会变得非常大(我看到的记录是 13k x 15k 像素)。问题是我可怜的 JVM 一直痛苦地死去和/或在图像开始变大时抛出 OutOfMemoryError。

这是我的 运行

//the bands, width, and height fields are set in the native code
//And the rawBytes array is also populated in the native code.

public BufferedImage getImage(){
    int type = bands == 1 ? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_INT_BRG;
    BufferedImage bi = new BufferedImage(width, height, type);
    ImageFilter filter = new RGBImageFilter(){
        @Override
        public int filterRGB(int x, int y, int rgb){
            int r, g, b;
            if (bands == 3) {
                r = (((int) rawBytes[y * (width / bands) * 3 + x * 3 + 2]) & 0xFF) << 16;
                g = (((int) rawBytes[y * (width / bands) * 3 + x * 3 + 1]) & 0xFF) << 8;
                b = (((int) rawBytes[y * (width / bands) * 3 + x * 3 + 0]) & 0xFF);
            } else {
                b = (((int) rawBytes[y * width + x]) & 0xFF);
                g = b << 8;
                r = b << 16;
            }
            return 0xFF000000 | r | g | b;
        }
    };

    //this is the problematic block
    ImageProducer ip = new FilteredImageSource(bi.getSource(), filter);
    Image i = Toolkit.getDefaultToolkit().createImage(ip);
    Graphics g = bi.createGraphics();
    //with this next line being where the error tends to occur.
    g.drawImage(i, 0, 0, null);
    return bi;
}

此代码段适用于大多数图片,只要它们不是大得令人发指。它的速度也很好。问题是 ImageBufferedImage 步骤上绘图会占用太多内存。

有什么方法可以跳过这一步,直接从原始字节转到缓冲图像吗?

使用来自 jai 的 RawImageInputStream。这确实需要了解有关 SampleModel 的信息,您似乎从本机代码中获得了这些信息。

另一种选择是将您的 rawBytes 放入 DataBuffer, then create a WritableRaster, and finally create a BufferedImage。 这基本上就是 RawImageInputStream 会做的。