Read region from very large image file in Java
Asked Answered
H

3

10

Is there a Java library that can read regions of very large image (e.g. JPEG) files (> 10,000 x 10,000 pixels) without keeping the whole image in memory.

Or alternatively, which Java library is capable of handling very large image files with a minimum of overhead.

Hardej answered 27/8, 2013 at 13:14 Comment(3)
Do you want to read a region in terms of a byte offset and length or a few pixels from the whole image?Nalda
A region in terms of pixels.Hardej
Alright, try out the answer I posted below.Nalda
S
12

Standard ImageIO allows you to read regions of (large) images without reading the entire image into memory first.

Rectangle sourceRegion = new Rectangle(x, y, w, h); // The region you want to extract

ImageInputStream stream = ImageIO.createImageInputStream(input); // File or input stream
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);

if (readers.hasNext()) {
    ImageReader reader = readers.next();
    reader.setInput(stream);

    ImageReadParam param = reader.getDefaultReadParam();
    param.setSourceRegion(sourceRegion); // Set region

    BufferedImage image = reader.read(0, param); // Will read only the region specified
}
Supercilious answered 28/8, 2013 at 9:27 Comment(2)
Hi! Thanks for that very nice code snipped. Is it actually possible to write a region to an image without reading the whole image? My region is only 100px in square and I like to store it at a certain location in an huge Jpeg.Originally
@Originally Yes, it might be possible in certain file formats. The ImageIO API supports it. But please ask a new question! :-)Supercilious
S
0

You can use, for example, RandomAccessFile to read from the middle of the file: but the issue is that whole jpeg image is compressed after DCT quantization (http://www.fileformat.info/mirror/egff/ch09_06.htm), so I don't think that it is possible to read a fragment without reading whole file to memory.

Sauder answered 27/8, 2013 at 13:36 Comment(1)
I have only superficial knowledge of JPEG and DCT quantization, but I believe DCT is applied to 8x8 pixel blocks and it should be possible to avoid decoding all blocks in order to get a region. Of course it is necessary to get some coefficients/information from other parts of the image, but this does not mean I have to read all data into memory... but I could be wrong.Hardej
N
0

You can use a BufferedImage to do what you need.

// Set these variables according to your requirements
int regionX, regionY, regionWidth, regionHeight;    

BufferedImage image = ImageIO.read(new File("/path/to/image.jpg"));
BufferedImage region = image.getSubimage(regionX, regionY, regionWidth, regionHeight);

And then you can process the region subimage however you want.

Nalda answered 27/8, 2013 at 15:54 Comment(2)
@Raman: you describe the standard approach that works well with moderately sized images. You read the whole image into a BufferedImage and then extract the region. My problem is that this requires a lot of memory with very large images, since all pixels are decoded and held in memory. For an image of size 20,000x30,000 this would require nearly 2GB of memory; plus, the decoder spends time on decoding pixels that are never used...Hardej
The read method will throw with width*height > Integer.MAX_VALUE!Distinguishing

© 2022 - 2024 — McMap. All rights reserved.