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.

f3lix
  • 29,500
  • 10
  • 66
  • 86

3 Answers3

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
}
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • 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. – Durin Jun 02 '14 at 16:34
  • @Durin Yes, it might be possible in certain file formats. The ImageIO API supports it. But please ask a new question! :-) – Harald K Jun 02 '14 at 17:42
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.

dbf
  • 6,399
  • 2
  • 38
  • 65
  • 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. – f3lix Aug 28 '13 at 09:19
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.

Raman Lalia
  • 245
  • 1
  • 5
  • 1
    @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... – f3lix Aug 28 '13 at 09:09