2010-03-30 7 views
6

J'écris une application qui lit et affiche des images comme ImageIcons (dans un JLabel), l'application doit être capable de supporter les jpegs et les bitmaps. Pour les jpeg, je trouve que passer le nom de fichier directement au constructeur ImageIcon fonctionne bien (même pour afficher deux grands jpeg), mais si j'utilise ImageIO.read pour obtenir l'image, puis passer l'image au constructeur ImageIcon, je obtenez une OutOfMemoryError (Java Heap Space) lorsque la seconde image est lue (en utilisant les mêmes images que précédemment). Pour les bitmaps, si j'essaie de lire en passant le nom de fichier à ImageIcon, rien n'est affiché, cependant en lisant l'image avec ImageIO.read et en utilisant cette image dans le constructeur ImageIcon fonctionne très bien. En lisant les autres messages du forum, je comprends que la raison pour laquelle les deux méthodes ne fonctionnent pas de la même manière pour les différents formats est liée aux problèmes de compatibilité de java avec les bitmaps, mais il existe un moyen de contourner la même méthode pour les bitmaps et jpegs sans OutOfMemoryError?Java: Lire des images et afficher comme un ImageIcon

(je voudrais éviter d'avoir à augmenter la taille du tas si possible!)

Le OutOfMemoryError est déclenché par cette ligne:

img = getFileContentsAsImage(file); 

et la définition de la méthode est:

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

La trace de pile est:

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

Veuillez publier un exemple de code qui déclenche OutOfMemoryError. – Thomas

Répondre

3

Vous manquez de mémoire car ImageIO.read() renvoie un BufferedImage non compressé qui est très volumineux et qui est conservé dans le tas car il est référencé par le ImageIcon. Cependant, les images renvoyées par Toolkit.createImage restent dans leur format compressé (en utilisant la classe ByteArrayImageSource privée.)

Vous ne pouvez pas lire un BMP en utilisant Toolkit.createImage (et même si vous pouviez il resterait encore non compressé en mémoire et vous courraient probablement sur de l'espace de tas encore) mais ce que vous pouvez faire est de lire l'image non compressée et l'enregistrer dans un tableau d'octets sous forme compressée, par exemple

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

De cette façon, la seule fois que le bitmap non compressé doit être conservée en mémoire est quand il est en cours de chargement ou rendu.

+0

Brilliant! Cela fonctionne parfaitement. Juste par intérêt pourquoi cette méthode fonctionne-t-elle uniquement en utilisant "PNG" comme formatName lors de l'utilisation d'un fichier bitmap? – 11helen

+0

Il doit s'agir d'un format lisible par Toolkit et un plugin ImageIO doit y être associé. Le format GIF fonctionnera probablement (mais il est limité à 8bpp, donc la qualité peut être réduite). JPEG fonctionnera également (mais fonctionne mieux pour les images photographiques, qui étaient probablement déjà au format JPEG donc il serait redondant.) – finnw

0

Avez-vous essayé?

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

Il ne semble pas fonctionner avec les bitmaps et échoue également avec les 2 grands jpegs: Exception dans le fil "Image Fetcher 0" java.lang.OutOfMemoryError: espace de tas 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) à sun.awt.image.ImageRepresentation.setPixels (ImageRepresentation.java:470) ... – 11helen

0

Vous ne pourriez pas manquer de mémoire? Je veux dire, l'erreur se produit-elle encore si vous exécutez java avec, disons, -Xmx1g?