2011-05-03 56 views
8

我试图让用户从他们的硬盘加载图像,并在GUI中以可视化的形式呈现这些图像作为缩略图列表(带有添加到JList的图标的JPanel)。我目前使用ImageIO.read()来获取一个BufferedImage,并为每个图像使用getScaledInstance(听说你不应该使用它)。在Java中没有内存问题的情况下将大图像作为缩略图加载?

它适合小图片,但加载超过四张照片(5000x3000或一些这样),我得到“java.lang.OutOfMemoryError:Java堆空间”。对全尺寸BufferedImage的引用没有保存,所以我认为垃圾收集器会处理它,只保留缩放图像(应该不会占用太多内存),但看起来并不像它。我也尝试过getRuntime().gc()和System.gc(),没有任何效果。

从文件加载缩放图像的任何好方法,没有运行到内存错误?很显然,很多软件都能够做到这一点,可能不是Java。外部库可以。


当前代码:

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

回答

8

的问题是在使用的BufferedImage本身。当文件被读入内存时,你将不在堆空间。根据具体情况,您可以使用图像阅读器,也可以增加堆的大小。

我建议您使用图像阅读器。例如获得的图像读取你的代码将是这样的:

// 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(); 

来源:你有,你可以得到高宽比的ImageReader http://www.exampledepot.com/egs/javax.imageio/DiscType.html

一个通过调用reader.getAspectRatio()

我不知道你如何从ImageReader到缩略图。

+0

优秀。在使用ImageReader.read(0,ImageReadParam)获取BufferedImage之前,使用ImageReadParam.getSourceSubSampling(wratio,hratio,0,0)可以很好地进行缩放。 – 2011-05-04 17:37:39

+0

@ SWEn0thing。酷我必须记住,如何获得缩略图。 – 2011-05-04 17:57:13

+3

我还需要添加以下电话。ImageReadParam params = reader.getDefaultReadParam(); reader.setInput(iis,true,true); params.setSourceSubsampling(width,height,0,0); – 2012-05-31 08:07:29

0

JVM具有缓存图像的恶习。一种解决方法是:

  1. 创建一个指向图像的InputStream
  2. 将整个图像数据读入byte[](使用标准I/O API - imageio等之外)。
  3. byte[]创建一个ByteArrayInputStream
  4. 使用ByteArrayInputStream作为ImageIO.read(InputStream)的来源。

由于JVM不知道从哪个资源获取图像字节,因此无法唯一标识图像,也不会缓存它。


请注意,我找不到任何支持我所说的文档。这只是从过去的经验。

相关问题