2010-03-30 14 views
6

Piszę aplikację, która odczytuje i wyświetla obrazy jako ImageIcons (w ramach JLabel), aplikacja musi obsługiwać jpeg i bitmapy.Java: Odczytywanie obrazów i wyświetlanie jako ImageIcon

Dla jpegs stwierdzam, że podanie nazwy pliku bezpośrednio do konstruktora ImageIcon działa poprawnie (nawet w przypadku wyświetlania dwóch dużych jpegów), jednak jeśli użyję ImageIO.read, aby uzyskać obraz, a następnie przekazać obraz do konstruktora ImageIcon, uzyskać OutOfMemoryError (Java Heap Space) po odczytaniu drugiego obrazu (przy użyciu tych samych obrazów, co wcześniej).

Dla bitmap, jeśli próbuję odczytać, przekazując nazwę pliku do ImageIcon, nic nie jest wyświetlane, jednak czytając obraz z ImageIO.read, a następnie używając tego obrazu w konstruktorze ImageIcon działa dobrze.

Rozumiem, czytając inne posty na forum, że powodem, dla którego obie metody nie działają tak samo dla różnych formatów, są problemy z kompatybilnością java z bitmapami, jednak istnieje sposób obejścia mojego problemu, aby można było używać ta sama metoda dla bitmap i jpegów bez OutOfMemoryError?

(chciałbym uniknąć konieczności zwiększyć rozmiar sterty, jeśli to możliwe!)

OutOfMemoryError jest wyzwalane przez tę linię:

img = getFileContentsAsImage(file); 

i definicji metody jest:

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

Śledzenie stosu:

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

Proszę napisać przykładowy kod, który wyzwala OutOfMemoryError. – Thomas

Odpowiedz

3

Brakuje Ci pamięci, ponieważ ImageIO.read() zwraca nieskompresowany BufferedImage, który jest bardzo duży i jest przechowywany w stercie, ponieważ jest on oznaczony przez ImageIcon. Jednak obrazy zwracane przez Toolkit.createImage pozostają w skompresowanym formacie (za pomocą prywatnej ByteArrayImageSource klasę.)

Nie można odczytać BMP używając Toolkit.createImage (a nawet jeśli można byłoby nadal pozostają bez kompresji w pamięci i będzie prawdopodobnie zabraknie przestrzeni sterty ponownie), ale możesz odczytać nieskompresowany obraz i zapisać go w tablicy bajtów w postaci skompresowanej, np.

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

W ten sposób tylko razem nieskompresowane bitmapy muszą być przechowywane w pamięci to, gdy jest załadowany lub renderowane.

+0

Genialny! To działa idealnie. Po prostu nie interesuje, dlaczego ta metoda działa tylko przy użyciu "PNG" jako nazwy formatu podczas korzystania z pliku bitmapy? – 11helen

+0

Musi to być format możliwy do odczytania przez Toolkit i musi istnieć wtyczka ImageIO. Prawdopodobnie działa GIF (ale jest ograniczony do 8bpp, więc jakość może zostać zmniejszona). JPEG również działa (ale działa najlepiej w przypadku zdjęć fotograficznych, które prawdopodobnie miały już format JPEG, więc byłoby zbędne). – finnw

0

Czy próbowałeś tego?

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

Wygląda na to, że nie działa z mapami bitowymi, a także nie działa z 2 dużymi jpegami: Wyjątek w wątku "Image Fetcher 0" java.lang.OutOfMemoryError: Przestrzeń sterty Java w java.awt.image.DataBufferInt. (DataBufferInt.java:41) w java.awt.image.Raster.createPackedRaster (Raster.java:458) w java.awt.image.DirectColorModel.createCompatibleWritableRaster (DirectColorModel.java:1015) w sun.awt. image.ImageRepresentation.createBufferedImage (ImageRepresentation.java:230) at sun.awt.image.ImageRepresentation.setPixels (ImageRepresentation.java:470) ... – 11helen

0

Nie może być tak, że rzeczywiście zabrakło Ci pamięci? Mam na myśli, czy błąd nadal występuje, jeśli uruchamiasz java z, powiedzmy, -Xmx1g?

Powiązane problemy