我正在编写一个应用程序,它以
ImageIcons(在JLabel中)读取和显示图像,应用程序需要能够支持jpeg和位图.
对于jpeg,我发现将文件名直接传递给ImageIcon构造函数工作正常(即使显示两个大型jpeg),但是如果我使用ImageIO.read获取图像然后将图像传递给ImageIcon构造函数,我会得到一个OutOfMemoryError( Java Heap Space)读取第二个图像时(使用与之前相同的图像).
对于位图,如果我尝试通过将文件名传递给ImageIcon来读取,则不显示任何内容,但是通过使用ImageIO.read读取图像然后在ImageIcon构造函数中使用此图像可以正常工作.
我从阅读其他论坛帖子中了解到,两种方法对于不同格式不起作用的原因归结为java与位图的兼容性问题,但是有一种方法可以绕过我的问题以便我可以使用相同的方法没有OutOfMemoryError的位图和jpegs?
(如果可能,我想避免增加堆大小!)
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)
解决方法
内存不足因为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());
- }
这样,无压缩位图必须保存在内存中的唯一时间是加载或渲染时.