2D-Grafik Diverse Fragen zu Imagemanipulation in Java

satou

Mitglied
Tag auch,

ich plane eine Bildverwaltung zu schreiben und hab da 3 fragen die mich seit einiger Zeit plagen, und zwar:

1.) Wie sieht die Speicherbelastung aus? Wenn mein Panel eine Dimension von 500x500 hat und ich dort ein Gird zum anzeigen von 9 skalierte Bilder als "Icon" darstellen möchte; 1.) Wird da das ganze Bild geladen und nur skaliert angezeigt, 2.) Wird es in den Speicher geladen, eine Kopie zum skalieren erstellt genutzt und beide Varianten hängen im Speicher?
2.) Wenn ich Bilder in meine Anwendung lade, zB per Selektion eines Knoten in einem Tree der das Filesystem abbildet, wie viele Bilder sollten idealerweiße geladen werden um weiteres nachladen zu "ersparen" (unabhängig von der Bildschirmauflösung)?
3.) Gibt es einen geeigneten Algorithmus zum anzeigen von Bildern?

Was Punkt 3 angeht hätte ich schon eine gewisse Vorstellung, bin mir aber nicht wirklich sicher ob das jetzt der ideale Weg zum Ziel ist, da ich mir hauptsächlich um den Speicherverbrauch gedanken mache:

Eine TreeNode wurde selektiert, eine Funktion greift sich rekursive alle jpgs, pngs, und gifs und steckt diese in eine Liste. Die Bildschirmauflösung ist analysiert und und legt die anzahl Grids in dem Panel zum anzeigen der Bilder fest (zB 9 Bilder im Anzeigebereich). Eine weitere Liste mit der Anzahl zu anzeigenden Bilder wird festgelegt inder sich die maximale Zahl der zu ladenden Bilder um 2 Reihen erweitert, für hoch und runter scrollen. Soll heißen, 9 Bilder sieht man, effektiv sind aber 15 Bilder geladen um ein Unterbrechen zu verhindern. Jenachdem in welche richtung der Balken gescrollt wird, zB nach unten, wird aus der Liste der Bilder im Anzeigebereich die ersten 3 Einträge gelöscht, der Inhalt repositioniert (um 3 zurück verschoben) und aus der Liste die die gespeicherten Pfade beinhält werden die nächsten 3 Bilder ans Ende der Bilderliste im Anzeigebereich hinzugefügt.

Wenn es jemand nicht verstanden hat, tut mir leid, ist nicht wirklich einfach zu erklären.

Würd mich über Antworten freuen



Mfg satou
 
Zuletzt bearbeitet:
Für ein Bild in der Auflösung 500x500 hast du mindestens einen Speicherverbrauch von 500x500x4 Byte = 1MB.
Genaueres kann man erst sagen, wenn man weiss wie du vorgehst.
In Java gibt es z.B. die Klasse java.awt.image.BufferedImage, die ein Bild darstellt. Man kann sich aber auch andere Darstellungen ausdenken.
Ich programmiere übrigens gerade an einem "IconEditor"; vielleicht ist das für dich interessant:

http://www.java-forum.org/codeschnipsel-u-projekte/105223-icon-editor.html
 
500x500 in 9 Grids so wie bei TicTacTo, also 9 sichtbare Bilder in einem Raster sortiert, bei dem jedes ca 166x166 +- insets groß ist. Bei der Grafik die eine Auflösung 500x500 hat, woher willst du da wissen das diese exakt 1MB Speicher belegt? Ich könnte ein Image haben welches vielleicht 50k hat aber die Auflösung von 500x500, deshalb ergibt das grade für mich wenig Sinn, warum das grade einen gigantischen MB frisst als die tatsächlichen größe der Datei. (Bitte nicht falsch verstehen, ich frag nur)
 
Zuletzt bearbeitet:
Da war ich wohl ein wenig vorschnell. Habe die Größe anhand meines eigenen Formats zum abspeichern berechnet. Mag sein, das es platzsparendere Formate gibt. Wie es sich bei dem weit verbreiteten BufferedImage verhält weiss ich leider nicht.
Tut mir leid, das ich dir nicht wirklich weiter helfen konnte.
Gruß Christian
 
Bei der Grafik die eine Auflösung 500x500 hat, woher willst du da wissen das diese exakt 1MB Speicher belegt? Ich könnte ein Image haben welches vielleicht 50k hat aber die Auflösung von 500x500, deshalb ergibt das grade für mich wenig Sinn, warum das grade einen gigantischen MB frisst als die tatsächlichen größe der Datei. (Bitte nicht falsch verstehen, ich frag nur)

Dran gedacht, dass Bilder in der regel komprimiert gespeichert werden?
 
ich plane eine Bildverwaltung zu schreiben und hab da 3 fragen die mich seit einiger Zeit plagen, und zwar:
ich mache zu Zeit was sehr ähnliches.

1.) Wie sieht die Speicherbelastung aus? Wenn mein Panel eine Dimension von 500x500 hat und ich dort ein Gird zum anzeigen von 9 skalierte Bilder als "Icon" darstellen möchte; 1.) Wird da das ganze Bild geladen und nur skaliert angezeigt, 2.) Wird es in den Speicher geladen, eine Kopie zum skalieren erstellt genutzt und beide Varianten hängen im Speicher?
das liegt alles in deiner Hand, Du kannst alles bis auf das Byte regeln. Mit ImageIO kannst Du entweder das ganze Bild laden und/oder nur eine verkleinerte Version. Weiterhin kannst Du ein Cache Management einrichten, nach dem Du entscheidest, welche Bilder wann geladen werden, welche im Speicher verbleiben und welche aus Speichermangel entladen werden, um diese beim späteren Bedarf wieder zu laden. Der Rest hängt von der Performance des Computers und den Wünschen des Anwenders ab.

2.) Wenn ich Bilder in meine Anwendung lade, zB per Selektion eines Knoten in einem Tree der das Filesystem abbildet, wie viele Bilder sollten idealerweiße geladen werden um weiteres nachladen zu "ersparen" (unabhängig von der Bildschirmauflösung)?
idealerweise so viele wie gerade benötigt. 🙂

3.) Gibt es einen geeigneten Algorithmus zum anzeigen von Bildern?
eine JList, ein eigener CellRenderer, ein eigenes ListModel, ein Thread, eine JProgressBar und ein Button zum Abbrechen/Pausieren für den Anwender.

Was Punkt 3 angeht hätte ich schon eine gewisse Vorstellung, bin mir aber nicht wirklich sicher ob das jetzt der ideale Weg zum Ziel ist, da ich mir hauptsächlich um den Speicherverbrauch gedanken mache:
Der Speicherverbrauch ist einfach die Variable N. Was N ist bestimmt der jeweilige Anwender auf seinem jeweiligen PC. Es kann nur 10MB sein oder auch 16GB.

Eine TreeNode wurde selektiert, eine Funktion greift sich rekursive alle jpgs, pngs, und gifs und steckt diese in eine Liste. Die Bildschirmauflösung ist analysiert und und legt die anzahl Grids in dem Panel zum anzeigen der Bilder fest (zB 9 Bilder im Anzeigebereich). Eine weitere Liste mit der Anzahl zu anzeigenden Bilder wird festgelegt inder sich die maximale Zahl der zu ladenden Bilder um 2 Reihen erweitert, für hoch und runter scrollen. Soll heißen, 9 Bilder sieht man, effektiv sind aber 15 Bilder geladen um ein Unterbrechen zu verhindern. Jenachdem in welche richtung der Balken gescrollt wird, zB nach unten, wird aus der Liste der Bilder im Anzeigebereich die ersten 3 Einträge gelöscht, der Inhalt repositioniert (um 3 zurück verschoben) und aus der Liste die die gespeicherten Pfade beinhält werden die nächsten 3 Bilder ans Ende der Bilderliste im Anzeigebereich hinzugefügt.
zu kompliziert. Du erstellst eine horizontale JList, mit einem eigenen Model und Renderer, und startest einen Thread, welcher die Bilder aus einer Quelle (z.B. Ordner) nacheinander (oder einem anderen Muster) lädt. Wenn ein Bild oder die Vorschau geladen wurde, wird es in das Model und so auch in die JList eingefügt. Die GUI wird nicht blockiert und so kann der Anwender die Bilder nacheinander sehen. Wie schnell das passiert, hängt von dem PC ab. Die JList kann der User selber auf die gewünschte Breite und Höhe ziehen. Mit einer JProgressBar wird angezeigt, wie viel noch zu laden ist. Das sollte der User abbrechen oder pausieren können. Wenn der User einen anderen Knoten auswählt (z.B. anderer Ordner), bricht der Lade-Thread seine Arbeit ab, wird auf diese Quelle umgeleitet und beginnt von vorne. Zusätzlich gibt es ein Cache-System. Wenn der festgesetzte Speicher zu Ende ist, werden die ältesten nicht verwendeten Bilder aus dem Speicher entfernt.

Für horizontale Listen findest Du hier eine Anleitung:

How to Use Lists (The Java™ Tutorials > Creating a GUI With JFC/Swing > Using Swing Components)

Slawa
 
500x500 in 9 Grids so wie bei TicTacTo, also 9 sichtbare Bilder in einem Raster sortiert, bei dem jedes ca 166x166 +- insets groß ist. Bei der Grafik die eine Auflösung 500x500 hat, woher willst du da wissen das diese exakt 1MB Speicher belegt? Ich könnte ein Image haben welches vielleicht 50k hat aber die Auflösung von 500x500, deshalb ergibt das grade für mich wenig Sinn, warum das grade einen gigantischen MB frisst als die tatsächlichen größe der Datei. (Bitte nicht falsch verstehen, ich frag nur)

Angenommen du willst dir keine Klasse selbst schreiben, die das Bild darstellen kann (recht komplex), dann musst du eine Standardklasse verwenden - wie bspw. das BufferedImage. Angenommen du möchtest im BufferedImage alle Farbkanäle (Rot, Grün, Blau) ohne den Alpha-Kanal anzeigen, dann benötigt jeder Farbkanal 8 Bit, also ein Byte. Du hast pro Pixel also 3 Byte im Speicher. Bei 500*500=250.000 Pixel und diese dann mal 3 Byte ergibt 750.000 Byte = 732KB.
 
Habe mal getested wieviel Speicher ein BufferedImage verbraucht.
Code:
package pack;
import java.awt.image.BufferedImage;
public class Main 
{
	public static void main(String[] args)
	{
		long l1 = Runtime.getRuntime().freeMemory();
		BufferedImage erg = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
		long l2 = Runtime.getRuntime().freeMemory();
		System.out.println(l1 + ":" + l2);
	}
}
Ergebnis:
4865672:3847064
Das heißt 1MB ist korrekt.
 
@slawaweis
Warum benötigt man einen Thread? Bei einem 100x100 Grid kann ich mir ja vorstellen warum, aber ich denke das der Prozessor zum bearbeiten und anzeigen von 25 Bildern in einem 5x5 Grid nicht grade auf Performanceprobleme stößt, ganze besonders die heutigen Prozessoren nicht.

ProgressBar ist meiner Meinung nach nicht nötig, da ich nicht von anfang an vorhabe alle Bilder direkt zu bearbeiten und anzuzeigen, sondern immer unmerklich, Stück für Stück, wenn's möglich ist. Progressbars stören mich persönlich. Ich würde das laden der Bilder abhängig von Userinput anzeigen, wenn er scrollt wird was neues geladen, wenn er's nicht tut dann halt nicht, somit sollte das ganze kompakt sein und auch unter ältern Geräten mit wenig Speicher und ältern CPUs, wie mein altes Denk-Brett von IBM, funktionieren.

@marge2010
Troll oder tl:dr?
 
Zuletzt bearbeitet:
tl:dr = to long, didn't read

Ich bin grundsätzlich immer von komprimierten Bildern ausgegangen, weshalb ich auch das geschrieben hab was marge2010 zitiert hab. Vielleicht hab ich's auch missverstanden.

@slawaweis

Danke für den Tipp bezüglich JList, ist um vieles komfortabler als mit einem Panel zu hantieren 🙂
 
Ich bin grundsätzlich immer von komprimierten Bildern ausgegangen, weshalb ich auch das geschrieben hab was marge2010 zitiert hab. Vielleicht hab ich's auch missverstanden.
Na wenn du das weißt versteh ich nicht was dein Problem mit der Rechnung von Homer ist.

Dass die Daten im Speicher unkomprimiert liegen müssen um das Bild zu zeichnen ist klar?
 

Zurück
Oben