2013-02-28 10 views
7

Chcę załadować duże obrazy (18000 x 18000) do mojej aplikacji. Jeśli używam BufferedImage z typem int_rgb, potrzebuję około 1235 MB pamięci sterty do załadowania. Jest to bardzo duża ilość pamięci, a użytkownicy końcowi prawdopodobnie będą mieli mniej pamięci RAM (1 GB lub mniej).Jak załadować olbrzymi obraz do Java za pośrednictwem BufferedImage?

Na moim komputerze deweloperskim, po załadowaniu obrazu z MyEclipse IDE, wyrzuca on brakującą pamięć Exception. Kiedy pakuję kod do pliku wykonywalnego jar i uruchamiam go na komputerze poza Eclipse, nadal generuje wyjątek.

Jak załadować tak duży obraz do mojej aplikacji przy użyciu buforowanego obrazu bez użycia 1235 MB pamięci? Czy jest jakaś sztuczka, np. Dzielenie obrazu na mniejsze części, takie jak segmentacja obrazu?

Znalazłem this thread on SO, ale nie było to dla mnie przydatne; Chcę załadować obraz do BufferedImage, a następnie narysować go na Panel przy użyciu klasy Graphics.

Odpowiedz

6

Możesz czytać i fragmenty wyświetlanie obrazu przy użyciu ImageReadParam z ImageIO opakowaniu. Oto prosty przykład, który ilustruje, jak czytać pojedynczy fragment z zastosowaniem ImageReadParam bez czytania całego obrazu:

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

Wynik wygląda tak:

enter image description here

+1

dziękuję za cenne uwagi i spróbuję tego i dam znać. – Mihir

+0

Z powodzeniem wdrożę Twoje rozwiązanie i zadziałało. Proszę, pomóż mi w tej sprawie, http://stackoverflow.com/questions/15438506/how-do-i-convert-an-enormous-tiff-image-to-png-jpeg-without-out-of-memory -błąd – Mihir

2

Generalnie trzeba by zrobić coś takiego:

  • Przerwa obraz w rozsądny rozmiar plików graficznych i zapisać je na dysku z aplikacją.
  • Podczas wyświetlania określonej części tego obrazu, tylko fragmenty obrazu obciążenia i obrazu nakładają się na rzutnię.
  • Podczas przesuwania obrazu, odpowiednio zaktualizuj wczytane i wyświetlone fragmenty obrazu.
  • Pozwól niech zbędne fragmenty obrazu zostaną zebrane przez GC lub załaduj nowe w taki sposób, aby nadpisały starsze. (Ten ostatni argument za identycznie wielkości fragmentów obrazu, które ładują się do zebranych buforach pamięci.)
+0

Zgadzam się z twoją teorią. w rzeczywistości cieszę się, że myślałem w tym samym kierunku, ale czy możesz podać mi przykłady lub fragmenty kodu? – Mihir

1

Kompletne rozwiązanie jest BigBufferedImage. Może załadować i przechowywać znacznie większe obrazy niż limit pamięci. Sztuką jest to, że jego bufor jest zastąpiony przez opartą na plikach implementację DataBuffera. Przechowuje obraz na dysku twardym. Brak pamięci RAM. To może zapobiec OutOfMemoryException.

Tworzenie BigBufferedImage z pliku obrazu:

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

Utwórz pusty BigBufferedImage:

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

renderować część obrazu:

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

Aby uzyskać więcej informacji na temat obsługi dużego obrazu read this article.

Powiązane problemy