# Bilder als "Thumbnails" laden - Performance



## Freecastle (19. Aug 2006)

Hallo,

ich habe ein Programm, welches unter anderem aus einem Ordner alle Bilder lädt und diese dann zur besseren Ansicht verkleinert (z.B. 64x64 Pixel) darstellt. Diese Bilder können bis zu 1,5 Mb groß sein. 
Wenn ich z.B. aus einem Ordner so an die 15 Bilder lade, dann dauert das schon *sehr* lange. Also ich denke 2-3 Minuten sind dafür absolut nicht akzeptabel. 
Meine Vorgehensweise ist die folgende: Ich lade jedes Bild der Reihe nach mit ImageIO.read(). Zum Skalieren erzeuge ich mit der Methode getScaledInstance() (von BufferedImage) ein Image das die korrekte Größe hat (also z.B. 64x64). Daraufhin erzeuge ich ein neues BufferedImage mit dieser Größe und zeichne mit drawImage() das skalierte Bild darauf. Dieses Image platziere ich dann in ein Panel (welches natürlich auch diese Größe hat). Funktionieren tut das einwandfrei... aber wie gesagt die Performance lässt sehr zu wünschen übrig. Da gibts doch bestimmt noch bessere Wege, damit das ganze effizienter wird, oder ?

Ich weiß auch nicht, ob das hier das richtige Forum dafür ist... evtl. passt das auch besser ins Swing-Forum...
Naja bin jedensfalls für jede Hilfe dankbar


----------



## Wildcard (19. Aug 2006)

2-3 minuten kommt mir da auch sehr lange vor. Poste mal butte deinen Code.


----------



## André Uhres (20. Aug 2006)

Neben der Codeoptimierung käme vielleicht auch ein Thumbnailsordner in Betracht, 
in welchem die Bilder als Thumbnails abgespeichert sind (Dateien im passenden Kleinformat).

Das Laden müsste ja rein theoretisch mit den kleineren Dateien schneller gehen.

Der Thumbnailsordner muss natürlich zuerst angelegt und gefüllt werden,
was wiederum zeitaufwendig sein mag, sich aber dennoch lohnen könnte im Fall wo die 
Bildersammlung ziemlich statisch ist und ein einmaliges/seltenes Erstellen der Thumbnails genügt.


----------



## Freecastle (20. Aug 2006)

Also ich habe eine Methode, welche die eigentliche Arbeit macht:


```
public final Image getScaledImage(File file, int width, int height) throws IOException {
		
		//Bild einlesen
		BufferedImage image = ImageIO.read(file); 
	
		//Skalieren...
		Image scaled = image.getScaledInstance(width,height,Image.SCALE_SMOOTH);
		
		//... und in einer neuen Image-Instanz das skalierte Bild speichern
		image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		image.createGraphics().drawImage(scaled,0,0,null);

		return image;
	}
```


Ich habe eine Collection, in welcher ich alle zu ladenden Bilder als File-Objekte drin habe. Diese iteriere ich in einer simplen For-Schleife durch und rufe dann eben für jede Datei diese Funktion auf (Gut, hinzu kommt dann eben noch Code um die Bilder in ein Array von Panels reinzuplatzieren, aber das ist hier auf keinen Fall der Flaschenhals, zudem erstelle ich das Panel-Array schon vorher).

Das mit dem Thumbnails-Ordner ist zwar eine gute Idee, kommt für mein Programm aber nicht in Betracht, da man mit dem Programm vielleicht einmal alle Bilder aus Ordner xyz öffnen will, und später dann vielleicht alle Bilder aus Ordner abc usw... Und auch nach Programmende wird man wohl so gut wie nie genau denselben Ordner noch einmal so öffnen wollen... 

Also mir ist sehr wohl bewusst, dass das schon seine Zeit brauchen kann viele (und vor allem auch große) Bilder in verkleinerter Ansicht ins Programm reinzuladen, aber wie gesagt eine Zeit von z.B. knapp 3 Minuten für ca 14-15 Bilder ist doch recht inakzeptabel, vor allem da es ja auch Anwendungen gibt die ähnliches *viel* effizienter leisten


----------



## André Uhres (20. Aug 2006)

Freecastle hat gesagt.:
			
		

> ..da es ja auch Anwendungen gibt die ähnliches *viel* effizienter leisten


Ich weiss nicht ob es dir hilft, aber hier ist die loadImage() Methode aus meinem Albumprogramm. 
In einem Test hat es 63 Bilder von insgesamt 25MB in 22 Sekunden als Thumbnails geladen.
Die Performanz hängt natürlich auch vom Rechner ab:

```
public void loadImage() {
        if (file == null) {
            thumbnail = null;
            return;
        }
        ImageIcon tmpIcon = new ImageIcon(file.getPath());
        if (tmpIcon != null) {
            if( tmpIcon.getIconWidth() >= tmpIcon.getIconHeight() ){
                //landscape
                if ( tmpIcon.getIconWidth() > dimemsion.width  ) {
                    thumbnail = new ImageIcon(tmpIcon.getImage().getScaledInstance(
                            dimemsion.width, -1, Image.SCALE_DEFAULT));
                } else { //no need to miniaturize
                    thumbnail = tmpIcon;
                }
            }else{
                //portrait
                if ( tmpIcon.getIconHeight() > dimemsion.height  ) {
                    thumbnail = new ImageIcon(tmpIcon.getImage().getScaledInstance(
                            -1, dimemsion.height, Image.SCALE_DEFAULT));
                } else { //no need to miniaturize
                    thumbnail = tmpIcon;
                }
            }
        }
    }
```
Mein Albumprogramm ist eigentlich eine Unterfunktion in meinem Malprogramm (Menüpunkt: Anzeigen | Album).
Es hat zwar auch noch einige Optimierungen nötig, aber hier kannst du die aktuelle Version schonmal 
runterladen zum Testen: http://www.geocities.com/uhrand/Malprogramm.zip


----------



## Freecastle (21. Aug 2006)

Deine loadImage()-Methode hat mir sehr geholfen 
Ich hab jetzt mal ne exakte Messung gemacht, und da wo ich vorher so 2-3 Minuten brauchte (konnte ich ja von meiner Uhr ablesen, da es so lange ging  ), braucht das Programm jetzt für 15 Bilder mit einer Gesamtgröße von ca. 22 MB relativ genau 19,9 s (also 20 s). Und das ist auf jeden Fall akzeptabel.
Ich hatte zu Beginn sogar auch einen ähnlichen Ansatz wie du, also dass ich die Bilder ohne ImageIO, sondern "normal" mit ImageIcons lade, aber ich hatte beim Skalieren einen Fehler drinnen, wodurch zwar die Bilder verkleinert dargestellt wurden, aber die Bilder trotzdem noch den gleichen Speicher belegten (ist mir jetzt auch grade erst durch deine Methode klar geworden). Und so hab ich da dann halt ständig OutOfMemory-Fehler gekriegt.
Also danke auf jeden Fall 

Mal noch ne andere Frage: Kann es eventuell noch lohnen etwas an den Compilereinstellungen zu verändern ? Also z.B. anstatt dynmaischer Bindung statische Bindung zu benutzen usw ?


----------



## Wildcard (21. Aug 2006)

@Freecastle
Wenn du dir ein Graphics Objekt erzeugst solltest du anschließend dispose() aufrufen um die Resourcen wieder freizugeben.


----------

