在Java中将大图像加载为缩略图而不存在内存问题?

在Java中将大图像加载为缩略图而不存在内存问题?,java,memory-management,image-processing,thumbnails,Java,Memory Management,Image Processing,Thumbnails,我试图让用户从硬盘加载图像,并在GUI中以缩略图列表的形式直观地显示这些图像(带有添加到JList的图标的JPanel)。我目前正在使用ImageIO.read()获取BuffereImage,并对每个映像使用GetScaleInstance(听说您不应该使用它) 它可以很好地处理小图像,但是加载了四张以上的照片(5000x3000或类似的照片),我得到了“java.lang.OutOfMemoryError:java堆空间”。未保存对完整大小BuffereImage的引用,因此我认为垃圾收集器

我试图让用户从硬盘加载图像,并在GUI中以缩略图列表的形式直观地显示这些图像(带有添加到JList的图标的JPanel)。我目前正在使用ImageIO.read()获取BuffereImage,并对每个映像使用GetScaleInstance(听说您不应该使用它)

它可以很好地处理小图像,但是加载了四张以上的照片(5000x3000或类似的照片),我得到了“java.lang.OutOfMemoryError:java堆空间”。未保存对完整大小BuffereImage的引用,因此我认为垃圾收集器会处理它,只保留缩放的映像(这不应该占用太多内存),但它看起来不像。我也使用了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));
}

问题在于BuffereImage本身的使用。当文件被读入内存时,堆空间就用完了。根据其用途,您可以使用图像读取器,也可以增加堆的大小

我建议你使用图像阅读器。例如,要获取图像读取器,您需要编写如下代码:

  // 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,则可以通过调用
reader.getAspectRatio()


我不知道你是如何从图像阅读器变成缩略图的

JVM有一个讨厌的习惯,就是缓存图像。绕过它的一种方法是:

  • 创建指向图像的
    InputStream
  • 将整个图像数据读入
    字节[]
    (使用标准I/O API-外部
    imageio
    等)
  • 字节[]
    创建一个
    ByteArrayInputStream
  • 使用
    ByteArrayInputStream
    作为
    ImageIO.read(InputStream)
    的源
  • 因为JVM不知道图像字节是从什么资源获得的,所以它无法唯一地标识图像,并且不会缓存它



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

    太好了。在使用ImageReader.read(0,ImageReadParam)获取BuffereImage之前,使用ImageReadParam.getSourceSubSampling(wratio,hratio,0,0)对其进行缩放非常有效。@SWEn0thing。酷,我必须记住如何获得缩略图。我还需要添加以下调用。ImageReadParam params=reader.getDefaultReadParam();reader.setInput(iis,true,true);参数设置资源子采样(宽度、高度、0、0);