Laden großer Bilder als Miniaturbilder ohne Speicherprobleme in Java?

8

Ich versuche, den Benutzer Bilder von seiner Festplatte laden zu lassen und diese visuell in der GUI als eine Liste von Thumbnails darzustellen (JPanels mit Symbolen, die zu einer JList hinzugefügt wurden). Ich verwende derzeit ImageIO.read (), um ein BufferedImage zu erhalten und getScaledInstance für jedes Bild zu verwenden (gehört, dass du das nicht verwenden solltest).

Es funktioniert ziemlich gut mit kleinen Bildern, aber das Laden von mehr als vier Fotos (5000x3000 oder so ähnlich) und ich bekomme "java.lang.OutOfMemoryError: Java Heap Space". Der Verweis auf die volle Größe von BufferedImage wird nicht gespeichert, daher dachte ich mir, dass der Garbage Collector darüber verfügen würde und nur das skalierte Bild behalten würde (was nicht viel Speicher benötigt), aber es scheint nicht so zu sein. Ich trete auch getRuntime (). Gc () und System.gc (), ohne Wirkung.

Gibt es eine gute Möglichkeit, skalierte Bilder aus einer Datei zu laden, ohne in Speicherfehler zu geraten? Offensichtlich schaffen es viele Software, genau das zu tun, vielleicht nicht in Java. Externe Bibliotheken sind in Ordnung.

Aktueller Code:

%Vor%     
Johannes Keinestam 03.05.2011, 19:27
quelle

2 Antworten

8

Das Problem liegt in der Verwendung von BufferedImage selbst. Zu dem Zeitpunkt, zu dem die Datei in den Speicher gelesen wird, ist der Heap-Speicherplatz erschöpft. Abhängig davon, was für Sie das ist, können Sie entweder einen Bildleser verwenden oder Sie können die Größe des Heapspeichers erhöhen.

Ich würde empfehlen, dass Sie einen Bildleser verwenden. Um zum Beispiel einen Bildleser zu bekommen, wäre Ihr Code etwa so:

%Vor%

Von: Ссылка

Wenn Sie den ImageReader haben, können Sie das Seitenverhältnis erhalten, indem Sie reader.getAspectRatio()

aufrufen

Ich bin mir nicht sicher, wie Sie von einem ImageReader zu einem Thumbnail gehen würden.

    
Karthik Ramachandran 03.05.2011, 19:56
quelle
0

Die JVM hat eine unangenehme Angewohnheit, Bilder zwischenzuspeichern. Ein Weg, um es zu umgehen, ist:

  1. Erstellen Sie ein InputStream , das auf das Bild zeigt.
  2. Lesen Sie die gesamten Bilddaten in ein byte[] (mit Standard-I / O-APIs - außerhalb von imageio usw.).
  3. Erstellen Sie ein ByteArrayInputStream von byte[] .
  4. Verwenden Sie ByteArrayInputStream als Quelle für ImageIO.read(InputStream) .

Da die JVM nicht weiß, von welcher Ressource die Bildbytes erhalten wurden, kann sie das Bild nicht eindeutig identifizieren und wird nicht zwischengespeichert.

Wohlgemerkt, ich kann keine Dokumentation finden, die das bestätigt, was ich sage. Dies ist nur aus der Vergangenheit.

    
Andrew Thompson 03.05.2011 20:19
quelle