如何检查图像是否太大而无法打开?

时间:2015-08-23 07:22:23

标签: java out-of-memory bufferedimage heap-memory

如果指定的图像文件包含的图像太大,则根据所需的内存加载它,会引发OutOfMemoryError。出于同样的原因,如果缩放操作的缩放因子会产生过大的图像,则会引发OutOfMemoryError,如下所示:

Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
    at java.awt.image.DataBufferInt.<init>(DataBufferInt.java:75)
    at java.awt.image.Raster.createPackedRaster(Raster.java:467)
    at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1032)
    at java.awt.image.BufferedImage.<init>(BufferedImage.java:340)
    at java.awt.image.AffineTransformOp.createCompatibleDestImage(AffineTransformOp.java:461)
    at java.awt.image.AffineTransformOp.filter(AffineTransformOp.java:226)

是否可以通过执行一些初步检查来防止发生此错误? 例如,如果应用程序确定可以通过可用内存量加载到内存中的最大图像大小(以像素为单位),则可以避免执行缩放,其结果图像的像素数将大于确定的限制。 / p>

如何使用要从文件中读取的图像处理上述问题?如何在不加载内存的情况下获取图像文件的大小?可以使用this Q&A中提出的解决方案来处理此问题:此解决方案非常快,因为从文件中读取图像大小,而不加载整个图像。

总结......

第一个目标包括执行初步检查以获得要显示的图像大小,而不加载整个图像:

  • 如果图片是图片文件,可以使用this Q&A中提出的解决方案来实现;
  • 如果目标图像是缩放过程的结果,只需将当前图像的大小乘以指定的比例因子。

在这两种情况下,您都会得到应该加载到内存中的图像大小,即像素总数。可以将此值与值限制进行比较。但是,如何计算这个数值限制?如何确定可用内存量可以加载到内存中的最大图像大小或最大像素数?

1 个答案:

答案 0 :(得分:4)

您似乎已经发现,通过查看链接的答案和评论,您可以获得给定格式的ImageReader,然后向读者询问最终图像的尺寸。但是,即使VM有足够的可用内存,请记住BufferedImage需要连续的内存块,并且可用的最大块可能比可用内存小很多,由于碎片化。 AFAIK没有API可以从VM中找到“最大连续内存块”的大小。

在尝试解码之前,可以通过使用这样的代码(为了便于阅读而简化)来预先创建图像:

ImageReader reader; // the reader for your format
reader.setInput(input); // your input

// Create image from type specifier
ImageTypeSpecifier spec = reader.getImageTypes(0).next();
BufferedImage destination = spec.createBufferedImage(reader.getWidth(), reader.getHeight();

ImageReadParam param = reader.getDefaultReadParam();
param.setDestination(destination);

reader.read(0, param);  // Image will be decoded to destination

但是,请记住,解码过程可能需要一些额外的内存用于数据结构,缓冲区等,以有效地解码图像。因此,即使您知道尺寸,或者甚至在内存中都有目标图像,仍然可能会在解码时耗尽内存。

(预先创建目标图片和流程使用的内存也适用于AffineTransformOp或任何BufferedImageOp,真的。

所以,我想我会提出第二个@skykings建议,你最终应该以某种方式处理OutOfMemoryError。几乎不可能保证你有足够的内存来预先解码给定的图像。