2010-03-30 76 views
6

我正在編寫一個應用程序,它讀取並顯示圖像作爲ImageIcons(在JLabel中),應用程序需要能夠支持jpegs和位圖。Java:讀取圖像並作爲ImageIcon顯示

對於jpegs,我發現將文件名直接傳遞給ImageIcon構造函數可以正常工作(即使是顯示兩個大的jpegs),但是如果我使用ImageIO.read獲取圖像並將圖像傳遞給ImageIcon構造函數,當讀取第二個圖像時(使用與以前相同的圖像),會出現OutOfMemoryError(Java堆空間)。

對於位圖,如果我嘗試通過將文件名傳遞給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) 
+0

請發佈一些觸發OutOfMemoryError的示例代碼。 – Thomas 2010-03-30 11:40:20

回答

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

這樣,唯一一次未壓縮的位圖必須在內存中保存是當它被加載或呈現。

+0

太棒了!這工作完美。出於興趣,爲什麼只有在使用位圖文件時使用「PNG」作爲formatName才能使用此方法? – 11helen 2010-03-30 13:27:34

+0

它需要是工具包可讀的格式,需要有一個ImageIO插件。 GIF可能會工作(但限於8bpp,因此質量可能會降低).JPEG也可以工作(但對於照片圖像來說效果最好,這可能是JPEG格式,因此它可能是多餘的。) – finnw 2010-03-30 14:06:25

0

你試過這個嗎?

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

它似乎並沒有與位圖一起工作,並且也未能通過2個大的jpegs: 線程「Image Fetcher 0」中的異常java.lang.OutOfMemoryError:Java堆空間 位於java.awt.image.DataBufferInt。 (DataBufferInt.java:41) 在java.awt.image.Raster.createPackedRaster(Raster.java:458) 在java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1015) 在sun.awt。 image.ImageRepresentation。createBufferedImage(ImageRepresentation.java:230) at sun.awt.image.ImageRepresentation.setPixels(ImageRepresentation.java:470) ... – 11helen 2010-03-30 12:07:38

0

這不可能是你真的只是用完內存?我的意思是,如果你運行java,例如-Xmx1g,錯誤仍然會發生?