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

Java 如何检查图像是否太大而无法打开?,java,out-of-memory,bufferedimage,heap-memory,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.

如果指定的图像文件包含的图像太大,就加载它所需的内存而言,将引发
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)
线程“AWT-EventQueue-0”java.lang.OutOfMemoryError中的异常:java堆空间 位于java.awt.image.DataBufferInt.(DataBufferInt.java:75) 位于java.awt.image.Raster.createPackedRaster(Raster.java:467) 位于java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1032) 位于java.awt.image.buffereImage。(buffereImage.java:340) 在java.awt.image.AffineTransformOp.createCompatibleDestImage(AffineTransformOp.java:461) 在java.awt.image.AffineTransformOp.filter中(AffineTransformOp.java:226) 是否可以通过执行一些初步检查来防止发生此错误? 例如,如果应用程序根据可用内存量确定可加载到内存中的最大图像大小(以像素为单位),则可以避免执行缩放,因为缩放后的图像的像素数将大于确定的限制

如何处理从文件中读取的图像的上述问题?如何在不将图像文件加载到内存的情况下获取图像文件的大小?使用中提出的解决方案可以解决此问题:此解决方案非常快速,因为图像大小是从文件中读取的,而无需加载整个图像

总之

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

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

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

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

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

然而,请记住,解码过程可能需要一点额外的内存用于数据结构、缓冲器等,以有效地解码图像。因此,即使您知道尺寸,或者甚至在内存中有目标图像,也有可能在解码时内存不足

(预先创建目标映像和该过程使用的内存也适用于
AffineTransformOp
或任何
BufferedImageOp
,实际上)


因此,我想我会支持@skykings的建议,您最终应该以某种方式处理
OutOfMemoryError
。实际上,不可能保证您有足够的内存预先解码给定的图像

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

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

然而,请记住,解码过程可能需要一点额外的内存用于数据结构、缓冲器等,以有效地解码图像。因此,即使您知道尺寸,或者甚至在内存中有目标图像,也有可能在解码时内存不足

(预先创建目标映像和该过程使用的内存也适用于
AffineTransformOp
或任何
BufferedImageOp
,实际上)


因此,我想我会支持@skykings的建议,您最终应该以某种方式处理
OutOfMemoryError
。实际上,不可能保证您有足够的内存预先解码给定的图像

您是否尝试过使用异常处理?这个答案看起来很有意义。@TarunGupta:谢谢!答案是提供一种从文件中获取图像大小的方法,而无需加载整个图像。为什么您不能捕获
OutOfMemoryException
?请注意,打开前的检查可能无法保证您会避免异常。是否尝试使用异常处理?这个答案看起来很有意义。@TarunGupta:谢谢!答案是提供一种从文件中获取图像大小的方法,而无需加载整个图像。为什么您不能捕获
OutOfMemoryException
?请注意,打开前的检查可能无法保证您会避免异常。
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