【问题标题】:Java: Reading images and displaying as an ImageIconJava:读取图像并显示为 ImageIcon
【发布时间】:2011-02-02 10:31:19
【问题描述】:

我正在编写一个应用程序,它将图像读取并显示为 ImageIcons(在 JLabel 中),该应用程序需要能够支持 jpegs 和位图。

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

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

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

(如果可能,我希望避免增加堆大小!)

OutOfMemoryError 由这一行触发:

img = getFileContentsAsImage(file); 

方法定义为:

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

堆栈跟踪是:

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)

【问题讨论】:

  • 请发布一些触发 OutOfMemoryError 的示例代码。

标签: java image memory bitmap jpeg


【解决方案1】:

你试过了吗?

ImageIcon im = new ImageIcon(Toolkit.getDefaultToolkit().createImage("filename"));

【讨论】:

  • 它似乎不适用于位图,并且 2 个大型 jpeg 也失败:线程“Image Fetcher 0”中的异常 java.lang.OutOfMemoryError:java.awt.image 处的 Java 堆空间.DataBufferInt.(DataBufferInt.java:41) 在 java.awt.image.Raster.createPackedRaster(Raster.java:458) 在 java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1015) 在太阳。 awt.image.ImageRepresentation.createBufferedImage(ImageRepresentation.java:230) 在 sun.awt.image.ImageRepresentation.setPixels(ImageRepresentation.java:470) ...
【解决方案2】:

你不会真的只是内存不足吗?我的意思是,如果您使用 -Xmx1g 运行 java,是否仍然会出现错误?

【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

    • 太棒了!这完美地工作。只是出于兴趣,为什么在使用位图文件时,这种方法只能通过使用“PNG”作为格式名来工作?
    • 它必须是 Toolkit 可读的格式,并且需要有一个 ImageIO 插件。 GIF 可能会工作(但限制为 8bpp,因此质量可能会降低。)JPEG 也可以工作(但最适合摄影图像,可能已经是 JPEG 格式,所以它是多余的。)
    猜你喜欢
    • 1970-01-01
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    • 2012-07-18
    • 2015-04-24
    • 1970-01-01
    相关资源
    最近更新 更多