Loading large images as thumbnails without memory issues in Java?

二次信任 提交于 2019-12-17 18:38:44

问题


I'm trying to let the user load images from their harddrive, and present these visually in the GUI as a list of thumbnails (JPanels with icons added to a JList). I'm currently using ImageIO.read() to get a BufferedImage and using getScaledInstance for each image (heard that you weren't supposed use that though).

It works reasonably well with small images, but loading more than four photographs (5000x3000 or some such) and I get "java.lang.OutOfMemoryError: Java heap space". The reference to the full size BufferedImage isn't saved, so I figured that the garbage collector would dispose of it and only keep the scaled image (which oughtn't take much memory), but it doesn't seem like it. I tread getRuntime().gc() and System.gc() as well, to no effect.

Any good way of loading scaled images from file, without running into memory errors? Obviously a lot of softwares manage to do this very thing, maybe not in Java though. External libraries are okay.


Current code:

BufferedImage unscaledImage = ImageIO.read(imageFile);

int unscaledHeight = unscaledImage.getHeight();
int unscaledWidth = unscaledImage.getWidth();

int imageRatio = unscaledHeight/unscaledWidth;

if (imageRatio >= 1) {
    return new ImageIcon(unscaledImage.getScaledInstance(width,-1,Image.SCALE_FAST));
} else {
    return new ImageIcon(unscaledImage.getScaledInstance(-1,height,Image.SCALE_FAST));
}

回答1:


The problem is in the use of BufferedImage itself. By the time the file is read into memory you'll be out of heap space. Depending on what this is for you can either use an image reader or you can increase the size of the heap.

I'd recommend that you use an image reader. For example to get an image reader you code would be something like this:

  // Create an image input stream on the image
    ImageInputStream iis = ImageIO.createImageInputStream(o);

    // Find all image readers that recognize the image format
    Iterator iter = ImageIO.getImageReaders(iis);
    if (!iter.hasNext()) {
        // No readers found
        return null;
    }

    // Use the first reader
    ImageReader reader = (ImageReader)iter.next();

From : http://www.exampledepot.com/egs/javax.imageio/DiscType.html

One you have the ImageReader you can get the aspect ration by calling reader.getAspectRatio()

I'm not sure how you'd go from an ImageReader to a thumbnail though.




回答2:


The JVM has a nasty habit of caching images. One way to get around it is to:

  1. Create an InputStream pointing to the image.
  2. Read the entire image data into a byte[] (using standard I/O APIs - outside imageio etc.).
  3. Create a ByteArrayInputStream from the byte[].
  4. Use the ByteArrayInputStream as a source for ImageIO.read(InputStream).

Because the JVM does not know from what resource the image bytes were obtained it is unable to uniquely identify the image, and will not cache it.


Mind you, I cannot find any documentation that backs up what I am saying. This is just from past experience.



来源:https://stackoverflow.com/questions/5874593/loading-large-images-as-thumbnails-without-memory-issues-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!