【问题标题】:Java ImageIO read image byte[] into pre-allocated BufferedImageJava ImageIO 将图像字节 [] 读入预分配的 BufferedImage
【发布时间】:2021-08-02 01:44:51
【问题描述】:

我正在使用 ImageIO 和 JAI,并希望将字节数组读入 BufferedImagebyte[] 包含 JP2000 编码图像的数据,它相当大,大约 100MB。我目前正在做类似的事情:

byte[] imageDataBytes = ...
InputStream imageStream = new ByteArrayInputStream(imageDataBytes);
BufferedImage imageData = ImageIO.read(imageStream);

似乎每次调用read() 时,ImageIO 都会创建一个new BufferedImage

问题:

有没有办法告诉 ImageIO 读取图像字节数据并将其解码为预先分配的可变 BufferedImage

我通过 Javadocs 进行了一些搜索,发现 BufferedImage 将其数据存储在 Raster 对象中,该对象将其数据存储在 DataBuffer 对象中。所以我知道现有的任何解决方案在技术上都不会写信给BufferedImage,而是直接写给DataBuffer

知道所有图像的大小相同可能会有所帮助:大约 10,000 x 10,000,因此读取的图像与缓冲图像不对齐应该没有任何问题。最终,我想要一个缓冲图像、光栅或数据缓冲区的对象池,并在每次使用 ImageIO 读取时从池中借用。类似这样的伪代码:

InputStream imageStream = new ByteArrayInputStream(imageDataBytes);
WritableRaster raster = ObjectPool.getAvailableRaster();
ImageIO.readToRaster(imageStream, raster);
BufferedImage imageData = new BufferedImage(raster);

我确信那里有一个简单的解决方案。任何帮助将不胜感激!

【问题讨论】:

  • ImageIO 将其工作委托给 ImageReader(和 Writers)。所有这些都是细节丰富的。我会首先寻找字节数组和字节数组输入流的替代方案。并寻找 JPEG2000 ImageReader。
  • 感谢您的回复,但是查看read() 方法的实现,它已经将字节流转换为图像阅读器。它的核心是调用一个抽象的 read() 方法,定义为:public abstract BufferedImage read(int imageIndex, ImageReadParam param)。有没有办法将已经实例化的BufferedImageWritableRaster 对象作为参数传递给read() 方法?
  • 澄清一下,“核心”读取方法属于 ImageReader 对象,但它没有实现。

标签: java arrays image memory bufferedimage


【解决方案1】:

对于那些发现自己处于这种情况的人,VGR 的回答很有效。我想专门为包含元数据的 JPEG-2000 图像添加它,使用

reader.setInput(stream, true, true);

而不是

reader.setInput(stream);

这避免了 NullPointer 异常。你可以在这里读更多关于它的内容: https://issues.apache.org/jira/browse/PDFBOX-2103

【讨论】:

    【解决方案2】:

    是的,你可以set the destination image 一个 ImageReadParam 对象。但是,需要注意的是:BufferedImage 必须具有与正在加载的图像匹配的 ColorModel 和 SampleModel。

    我不确定 JPEG2000 图像,但常规 JPEG 通常是 RGB 图像,所以 TYPE_INT_RGB 的图像就足够了:

    BufferedImage image = new BufferedImage(10000, 10000,
        BufferedImage.TYPE_INT_RGB);
    
    while (bytesAvailable) {
        byte[] imageDataBytes = getImageBytes();
    
        try (InputStream in = new ByteArrayInputStream(imageDataBytes);
             ImageInputStream stream = ImageIO.createImageInputStream(in)) {
    
            ImageReader reader = ImageIO.getImageReaders(stream).next();
            reader.setInput(stream);
    
            ImageReadParam param = reader.getDefaultReadParam();
            param.setDestination(image);
    
            reader.read(0, param);
        }
    }
    

    【讨论】:

    • 非常感谢您的回复!只是好奇,将 try 块放在 while 循环之外是否明智,这样我就不会创建这么多输入流,或者我错过了什么?
    • @billschmidt626 您需要为每个字节数组创建一个新的 ImageInputStream。
    • 你是说我需要多个输入流来处理一张图片吗?对于您提到的getImageBytes() 方法,它是返回整个图像,还是不同的图像,或者图像的不同图块,或者只是图像字节的块?
    • 我假设 getImageBytes 是一种返回 JPEG 字节的方法,编码为 JPEG。我还假设您的每个图像都是不同的字节数组。
    • 啊,好吧。现在我明白了,您已经编写它来处理多个图像。比我早两步!再次感谢。
    猜你喜欢
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    相关资源
    最近更新 更多