Search code examples
javaarraysimagememorybufferedimage

Java ImageIO read image byte[] into pre-allocated BufferedImage


I'm working with ImageIO and JAI and want to read a byte array into a BufferedImage. The byte[] contains data for a JP2000 encoded image, and it's fairly large, around 100MB. I'm currently doing something like:

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

It seems that ImageIO is creating a new BufferedImage each time read() is called.

Question:

Is there a way to tell ImageIO to read and decode the image byte data into a pre-allocated mutable BufferedImage?

I did some searching through the Javadocs and found that the BufferedImage stores its data in a Raster object, which stores its data in a DataBuffer object. So I'm aware any solution that exists will technically not be writing to the BufferedImage, but instead will be directly writing to the DataBuffer.

It may help to know that all images are the same size: roughly 10,000 x 10,000, so there shouldn't be any problems with the read image not aligning with the buffered image. Ultimately, I would like to have an object pool of buffered images, or rasters, or data buffers, and borrow from the pool every time I read using ImageIO. Something like this pseudocode:

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

I'm sure there's a simple solution out there. Any help would be appreciated!


Solution

  • Yes, you can set the destination image of an ImageReadParam object. However, there is a caveat: the BufferedImage must have a ColorModel and SampleModel that match the image being loaded.

    I’m not sure about JPEG2000 images, but regular JPEGs are usually RGB images, so an image of TYPE_INT_RGB should suffice:

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