2013-02-28 9 views
7

Desidero caricare immagini di grandi dimensioni (18000 x 18000) sulla mia applicazione. Se uso BufferedImage con tipo int_rgb, ho bisogno di circa 1235 MB di memoria heap da caricare. Si tratta di una quantità di memoria molto elevata e gli utenti finali probabilmente avranno meno RAM (1 GB o meno).Come caricare un'immagine enorme su Java tramite BufferedImage?

Sul mio PC di sviluppo, quando carico l'immagine da MyEclipse IDE, getta una memoria esaurita Exception. Quando impacchetta il mio codice su un jar eseguibile e lo eseguo sul mio PC esterno a Eclipse, genera comunque un'eccezione.

Come caricare un'immagine di grandi dimensioni nella mia applicazione utilizzando l'immagine bufferizzata senza utilizzare 1235 MB di memoria? C'è un trucco, come dividere l'immagine in porzioni più piccole come la segmentazione delle immagini?

Ho trovato this thread on SO, ma non utile per me; Voglio caricare l'immagine in BufferedImage e quindi disegnarla su un Panel utilizzando la classe Graphics.

risposta

6

È possibile leggere e visualizzare frammenti dell'immagine utilizzando ImageReadParam da ImageIO pacchetto. Ecco un esempio di base che illustra come leggere un singolo frammento utilizzando ImageReadParam senza leggere l'intera immagine:

import java.awt.Image; 
import java.awt.Rectangle; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.URL; 

import javax.imageio.ImageIO; 
import javax.imageio.ImageReadParam; 
import javax.imageio.ImageReader; 
import javax.imageio.stream.ImageInputStream; 
import javax.swing.*; 

public class TestImageChunks { 
    private static void createAndShowUI() { 
     try { 
      URL url = new URL(
        "http://duke.kenai.com/wave/.Midsize/Wave.png.png"); 
      Image chunk = readFragment(url.openStream(), new Rectangle(150, 
        150, 300, 250)); 
      JOptionPane.showMessageDialog(null, new ImageIcon(chunk), "Duke", 
        JOptionPane.INFORMATION_MESSAGE); 
     } catch (IOException e) { 
      JOptionPane.showMessageDialog(null, e.getMessage(), "Failure", 
        JOptionPane.ERROR_MESSAGE); 
      e.printStackTrace(); 
     } 
    } 

    public static BufferedImage readFragment(InputStream stream, Rectangle rect) 
      throws IOException { 
     ImageInputStream imageStream = ImageIO.createImageInputStream(stream); 
     ImageReader reader = ImageIO.getImageReaders(imageStream).next(); 
     ImageReadParam param = reader.getDefaultReadParam(); 

     param.setSourceRegion(rect); 
     reader.setInput(imageStream, true, true); 
     BufferedImage image = reader.read(0, param); 

     reader.dispose(); 
     imageStream.close(); 

     return image; 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 

Il risultato è simile al seguente:

enter image description here

+1

grazie per i tuoi preziosi commenti e proverò questo e ti faccio sapere. – Mihir

+0

ho implementato con successo la tua soluzione e ha funzionato. per favore, aiutami anche su questo problema http://stackoverflow.com/questions/15438506/how-do-i-convert-an-enormous-tiff-image-to-png-jpeg-without-out-memory -errore – Mihir

2

In genere, avresti bisogno di fare qualcosa di simile:

  • Rompere l'immagine in file immagine dimensione gestibile e memorizzarli sul disco con l'applicazione.
  • Quando si visualizza una parte particolare di questa immagine, solo i frammenti di immagine di caricamento e visualizzazione si sovrappongono al viewport.
  • Mentre si ruota intorno all'immagine, aggiornare i frammenti di immagine caricati e visualizzati in modo appropriato.
  • O lasciare che i frammenti di immagine non necessari vengano raccolti dal GC o caricarne di nuovi in ​​modo che sovrascrivano quelli più vecchi. (Quest'ultima sostiene per frammenti di immagini identiche dimensioni che caricano nel buffer di memoria pool.)
+0

sono d'accordo con la tua teoria. in effetti sono contento di aver pensato nella stessa direzione, ma puoi darmi un esempio o frammenti di codice? – Mihir

1

Una soluzione completa è BigBufferedImage. Può caricare e memorizzare immagini molto più grandi del limite di memoria. Il trucco è che il suo buffer viene sostituito con un'implementazione basata su file di DataBuffer. Memorizza l'immagine sul disco rigido. Non viene utilizzata RAM. Questo può prevenire OutOfMemoryException.

Creare un BigBufferedImage da un file immagine:

BigBufferedImage image = BigBufferedImage.create(
     inputFile, tempDir, TYPE_INT_RGB); 

Creare un BigBufferedImage vuoto:

BigBufferedImage image = BigBufferedImage.create(
     tempDir, width, height, TYPE_INT_RGB); 

rendere la parte dell'immagine:

part = image.getSubimage(x, y, width, height); 

Per ulteriori informazioni sulla gestione delle immagini grandi read this article.