How to upload a huge image in Java via BufferedImage?

I want to upload large images (18000 x 18000) to my application. If I use BufferedImage with type int_rgb , I need about 1235 MB of heap memory to load. This is a very large amount of memory, and end users are likely to have less bar (1 GB or less).

On my development computer, when I load an image from MyEclipse IDE, it throws an Exception from memory. When I pack my code in an executable jar and run it on an external Eclipse computer, it still throws an exception.

How to load such a large image into my application using a buffered image without using 1235 MB of memory? Is there a trick, for example, splitting an image into smaller parts such as image segmentation?

I found this topic on SO , but it is not useful to me; I want to load an image into a BufferedImage , and then draw it on the Panel using the Graphics class.

+7
source share
3 answers

You can read and display fragments of the image using ImageReadParam from the ImageIO package. Here is a basic example illustrating how to read a single fragment using ImageReadParam without reading the entire image:

 import java.awt.Image; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.net.URL; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import javax.swing.*; public class TestImageChunks { private static void createAndShowUI() { try { URL url = new URL( "http://duke.kenai.com/wave/.Midsize/Wave.png.png"); Image chunk = readFragment(url.openStream(), new Rectangle(150, 150, 300, 250)); JOptionPane.showMessageDialog(null, new ImageIcon(chunk), "Duke", JOptionPane.INFORMATION_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(null, e.getMessage(), "Failure", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } public static BufferedImage readFragment(InputStream stream, Rectangle rect) throws IOException { ImageInputStream imageStream = ImageIO.createImageInputStream(stream); ImageReader reader = ImageIO.getImageReaders(imageStream).next(); ImageReadParam param = reader.getDefaultReadParam(); param.setSourceRegion(rect); reader.setInput(imageStream, true, true); BufferedImage image = reader.read(0, param); reader.dispose(); imageStream.close(); return image; } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowUI(); } }); } } 

The result is as follows:

enter image description here

+6
source

Typically, you need to do something like this:

  • Split the image into image files with a manageable size and save them to disk using your application.
  • When displaying a specific part of this image, only fragments of the loading and display image that overlap your viewport are displayed.
  • When panning an image, update the downloaded and displayed fragments of the image accordingly.
  • Either allow unnecessary fragments of images to be collected by the GC or upload new ones so that they overwrite the old ones. (The latter claims that fragments of the same size image are loaded into pools with buffer memory.)
+2
source

Complete BigBufferedImage solution. It can load and store much larger images than the memory limit. The trick is that its buffer is replaced by a file implementation of DataBuffer. It saves the image on the hard drive. RAM is not used. This may prevent an OutOfMemoryException.

Create the BigBufferedImage file from the image file:

 BigBufferedImage image = BigBufferedImage.create( inputFile, tempDir, TYPE_INT_RGB); 

Create an empty BigBufferedImage:

 BigBufferedImage image = BigBufferedImage.create( tempDir, width, height, TYPE_INT_RGB); 

Display part of image:

  part = image.getSubimage(x, y, width, height); 

For more information on large image processing, read this article .

+1
source