2010-03-30 42 views
6

Estoy escribiendo una aplicación que lee y muestra imágenes como ImageIcons (dentro de un JLabel), la aplicación necesita ser capaz de soportar jpegs y bitmaps.Java: Lectura de imágenes y visualización como ImageIcon

Para jpegs encuentro que pasar el nombre de archivo directamente al constructor ImageIcon funciona bien (incluso para mostrar dos jpegs grandes), sin embargo, si uso ImageIO.read para obtener la imagen y luego paso la imagen al constructor ImageIcon, obtener un OutOfMemoryError (Java Heap Space) cuando se lee la segunda imagen (usando las mismas imágenes que antes).

Para mapas de bits, si trato de leer pasando el nombre del archivo a ImageIcon, no se muestra nada, sin embargo leyendo la imagen con ImageIO.read y luego usando esta imagen en el constructor ImageIcon funciona bien.

Entiendo por leer en otros mensajes del foro que la razón de que los dos métodos no funcionen igual para los diferentes formatos es por problemas de compatibilidad de java con mapas de bits, pero hay una forma de solucionar mi problema para poder usar el mismo método para ambos mapas de bits y jpegs sin un OutOfMemoryError?

(me gustaría no tener que aumentar el tamaño de la pila si es posible!)

El OutOfMemoryError se desencadena por esta línea:

img = getFileContentsAsImage(file); 

y la definición del método es:

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

El seguimiento de la pila es:

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

Por favor, publique código de muestra que active OutOfMemoryError. – Thomas

Respuesta

3

Se está quedando sin memoria porque ImageIO.read() devuelve un BufferedImage descomprimido que es muy grande y se conserva en el montón porque se hace referencia en ImageIcon. Sin embargo, las imágenes enviadas por Toolkit.createImage permanecen en su formato comprimido (utilizando la clase privada ByteArrayImageSource.)

No se puede leer un BMP usando Toolkit.createImage (e incluso si pudiera seguiría siendo sin comprimir en la memoria y que probablemente agotado del espacio del montón de nuevo) pero lo que puede hacer es leer la imagen descomprimida y guardarla en una matriz de bytes en forma comprimida, por ejemplo

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 esta forma, la única vez que el mapa de bits descomprimido debe mantenerse en la memoria es cuando se carga o se procesa.

+0

¡Brillante! Esto funciona perfectamente Solo por interés, ¿por qué este método solo funciona al usar "PNG" como formatName cuando se usa un archivo de mapa de bits? – 11helen

+0

Tiene que ser un formato legible por el Toolkit y debe haber un complemento de ImageIO para él. GIF probablemente funcionará (pero está limitado a 8bpp, por lo que la calidad puede reducirse). JPEG también funcionará (pero funciona mejor para imágenes fotográficas, que probablemente ya estaban en formato JPEG, por lo que sería redundante). – finnw

0

¿Has probado esto?

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

Parece que no funciona con los mapas de bits y también falla con los 2 jpegs grandes: Excepción en el hilo "Image Fetcher 0" java.lang.OutOfMemoryError: espacio en el montón de Java en java.awt.image.DataBufferInt. (DataBufferInt.java:41) en java.awt.image.Raster.createPackedRaster (Raster.java:458) en java.awt.image.DirectColorModel.createCompatibleWritableRaster (DirectColorModel.java:1015) en sun.awt. image.ImageRepresentation.createBufferedImage (ImageRepresentation.java:230) at sun.awt.image.ImageRepresentation.setPixels (ImageRepresentation.java:470) ... – 11helen

0

¿No es cierto que se ha quedado sin memoria? Quiero decir, ¿el error todavía ocurre si ejecuta Java con, digamos, -Xmx1g?

Cuestiones relacionadas