Java:读取图像并显示为ImageIcon

11h*_*len 7 java memory jpeg image bitmap

我正在编写一个应用程序,它以ImageIcons(在JLabel中)读取和显示图像,应用程序需要能够支持jpeg和位图.

对于jpegs,我发现将文件名直接传递给ImageIcon构造函数工作正常(即使显示两个大的jpeg),但是如果我使用ImageIO.read获取图像然后将图像传递给ImageIcon构造函数,我会得到一个OutOfMemoryError( Java Heap Space)读取第二个图像时(使用与之前相同的图像).

对于位图,如果我尝试通过将文件名传递给ImageIcon来读取,则不会显示任何内容,但是通过使用ImageIO.read读取图像然后在ImageIcon构造函数中使用此图像可以正常工作.

我从阅读其他论坛帖子中了解到,两种方法对于不同格式不起作用的原因归结为java与位图的兼容性问题,但是有一种解决我的问题的方法,以便我可以使用相同的方法没有OutOfMemoryError的位图和jpegs?

(如果可能的话,我想避免增加堆大小!)

OutOfMemoryError由此行触发:

img = getFileContentsAsImage(file); 
Run Code Online (Sandbox Code Playgroud)

方法定义是:

public static BufferedImage getFileContentsAsImage(File file) throws FileNotFoundException { 
  BufferedImage img = null; 
  try { 
    ImageIO.setUseCache(false); 
    img = ImageIO.read(file); 
    img.flush(); 
  } catch (IOException ex) { 
    //log error 
  } 
return img; 
}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪是:

Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
        at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:58)
        at java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:397)
        at java.awt.image.Raster.createWritableRaster(Raster.java:938)
        at javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1056)
        at javax.imageio.ImageReader.getDestination(ImageReader.java:2879)
        at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:925)
        at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:897)
        at javax.imageio.ImageIO.read(ImageIO.java:1422)
        at javax.imageio.ImageIO.read(ImageIO.java:1282)
        at framework.FileUtils.getFileContentsAsImage(FileUtils.java:33)
Run Code Online (Sandbox Code Playgroud)

fin*_*nnw 3

您的内存不足,因为ImageIO.read()返回一个未压缩的文件BufferedImage,该文件非常大并且保留在堆中,因为它被ImageIcon. 但是,返回的图像Toolkit.createImage仍保持其压缩格式(使用私有ByteArrayImageSource类。)

您无法使用读取 BMP Toolkit.createImage(即使可以,它仍然会在内存中保持未压缩状态,并且您可能会再次耗尽堆空间),但您可以做的是读取未压缩图像并将其以压缩形式保存在字节数组中,例如

public static ImageIcon getPNGIconFromFile(File file) throws IOException {
    BufferedImage bitmap = ImageIO.read(file);
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    ImageIO.write(bitmap, "PNG", bytes);
    return new ImageIcon(bytes.toByteArray());
}
Run Code Online (Sandbox Code Playgroud)

这样,未压缩位图必须保存在内存中的唯一时间就是加载或渲染时。