2011-05-03 13 views
8

estoy tratando de dejar que las imágenes de carga de usuarios de su disco duro, y presentarlas visualmente en la interfaz gráfica de usuario como una lista de miniaturas (JPanels con iconos añaden a un JList). Actualmente estoy usando ImageIO.read() para obtener un BufferedImage y el uso de getScaledInstance para cada imagen (oído que no se suponía que el uso sin embargo).Cargando imágenes grandes como miniaturas sin problemas de memoria en Java?

Funciona razonablemente bien con pequeñas imágenes, pero la carga de más de cuatro fotografías (5000x3000 o algo así) y me sale "java.lang.OutOfMemoryError: espacio de almacenamiento dinámico de Java". La referencia a la BufferedImage tamaño completo no se guarda, por lo que pensé que el recolector de basura sería disponer de él y sólo mantener la imagen escalada (que no debiera tener tanta memoria), pero no lo parece. Pisé getRuntime(). Gc() y System.gc() también, sin ningún efecto.

¿Alguna buena forma de cargar imágenes escaladas desde un archivo, sin ejecutar errores de memoria? Obviamente, muchos softwares logran hacer esto mismo, aunque tal vez no en Java. Las bibliotecas externas están bien.


código actual:

BufferedImage unscaledImage = ImageIO.read(imageFile); 

int unscaledHeight = unscaledImage.getHeight(); 
int unscaledWidth = unscaledImage.getWidth(); 

int imageRatio = unscaledHeight/unscaledWidth; 

if (imageRatio >= 1) { 
    return new ImageIcon(unscaledImage.getScaledInstance(width,-1,Image.SCALE_FAST)); 
} else { 
    return new ImageIcon(unscaledImage.getScaledInstance(-1,height,Image.SCALE_FAST)); 
} 

Respuesta

8

El problema está en el uso de la misma BufferedImage. Para cuando el archivo se lea en la memoria, estarás fuera del espacio de montón. Dependiendo de para qué sirve esto, puede usar un lector de imágenes o puede aumentar el tamaño del montón.

Yo recomendaría que utilice un lector de imágenes. Por ejemplo, para obtener un lector de imágenes que código sería algo como esto:

// Create an image input stream on the image 
    ImageInputStream iis = ImageIO.createImageInputStream(o); 

    // Find all image readers that recognize the image format 
    Iterator iter = ImageIO.getImageReaders(iis); 
    if (!iter.hasNext()) { 
     // No readers found 
     return null; 
    } 

    // Use the first reader 
    ImageReader reader = (ImageReader)iter.next(); 

Desde: http://www.exampledepot.com/egs/javax.imageio/DiscType.html

Uno usted tiene la ImageReader se puede obtener la relación de aspecto llamando reader.getAspectRatio()

estoy sin embargo, no estoy seguro de cómo pasaría de un ImageReader a una miniatura.

+0

excelente. Funciona muy bien usando ImageReadParam.getSourceSubSampling (wratio, hratio, 0, 0) a escala que antes de conseguir el BufferedImage con ImageReader.read (0, ImageReadParam). –

+0

@ SWEn0thing. Genial, tendré que recordarlo para saber cómo obtener una miniatura. –

+3

Necesitaba agregar llamar lo siguiente también.ImageReadParam params = reader.getDefaultReadParam(); reader.setInput (iis, true, true); params.setSourceSubsampling (ancho, alto, 0, 0); –

0

La JVM tiene una mala costumbre de almacenar en caché las imágenes. Una manera de conseguir alrededor de él es:

  1. Crear un señalador InputStream a la imagen.
  2. Lea toda la información de la imagen en un byte[] (utilizando las API estándar de E/S - fuera de imageio etc.).
  3. Crea un ByteArrayInputStream del byte[].
  4. Utilice ByteArrayInputStream como fuente para ImageIO.read(InputStream).

Debido a que la JVM no sabe de qué recurso los bytes imagen se obtuvieron no es capaz de identificar de forma exclusiva la imagen, y no almacenar en caché.


Tenga en cuenta que no puedo encontrar ninguna documentación que respalde lo que estoy diciendo. Esto es solo por experiencia pasada.

Cuestiones relacionadas