Entwickler-Ecke

Multimedia / Grafik - imageList nach Laden statt 9 jetzt 170 MB groß


DJ Raptor - Do 24.06.04 15:14
Titel: imageList nach Laden statt 9 jetzt 170 MB groß
In einem Bildverwaltungsprogramm für Fotografen lade ich Bilder von der Festplatte per LoadFromFile Anweisung in eine imageList um die Daten später ohne Verzögerung anzeigen zu können. Allerdings steigt die Speicherauslastung meines Programms nach dem laden der Bilder in Dimensionen die in keinem Zusammenhang mehr stehen (zB laden von 23 Bilder mit einer Gesamtgröße von 9 MB, Speicherverbrauch des Programms ca 170 MB). Habe zwar beim Suchen einen Hinweis auf Fehler in der Speicherverwaltung von Delphi gefunden aber keinen konkreten Hinweis zur Lösung meines Problems. Ich verwende die imageList32 Komponente der graphics32 Library (g32.org), das Problem taucht aber auch bei der normalen imageList auf. Hoffe auf einige Lösungsvorschläge.


sourcehunter - Do 24.06.04 15:54

Kann es sein, dass die Bilder komprimiert sind? Außerdem musst den ganzen "Verwaltungskram" mit beachten. Aber ich denke das rechtfertigt nicht diese gigantische Aufblähung.


Gausi - Do 24.06.04 15:56

Hallo und :welcome:
Mal ins blaue geraten...lädst du vielleicht Jpgs in eine TBitmap-ähnliche Struktur? Ansonsten kann ich nur sagen, dass meine Kristallkugel bei diesem *?)/"%&-Wetter nicht funktioniert...zuviele atmosphärische Störungen...


Muetze1 - Do 24.06.04 16:11

Moin!

Gausi hats schon angedeutet: Eine TImageList hält die Bilder intern verlustfrei in einm grossen Bitmap wo die Einzelbilder einfach nacheinander aufgereiht werden. Daher werden eingeladene, komprimierte Bilder entpackt und dann in der ImageList gespeichert. Daher wird der grosse Speicherverbrauch kommen.

MfG
Muetze1


DJ Raptor - Do 24.06.04 17:29

ok, das erklärt dann schon mal einiges. Es handelt sich in der Tat in erster Linie um JPEG Bilder. Die Komponente der graphics32 Library speichert die geladenen Bilder jedoch jeweils als eigenständiges Bitmap ab und nicht als ein Großes wie bei der originalen imageList. Welche Möglichkeit gibt es denn die Bilder in komprimierter Form in eine imageList bzw. in den Speicher zu laden damit ich diese verzögerungsfrei anzeigen kann. Hab schon nach alternativen imageList Komponenten gesucht aber leider nix gefunden. Bin nach wie vor für jeden Tip dankbar ...


Muetze1 - Do 24.06.04 18:02

Moin!

Naja, verzögerungsfrei sind die JPEGs nicht, da sie erstmal dekomprimiert werden müssen und zum Teil braucht er dazu mehr Durchläufe...

Ansonsten: die Bitmaps sind schon reine Pixeldaten, ergo: warum lässt du es nicht so?

MfG
Muetze1


DJ Raptor - Do 24.06.04 18:09

naja das dekomprimieren wird aber vermutlich nicht so lange dauern wie das laden von platte sobald die datei benötigt wird. wenn ich es so lasse habe ich eben eine auslastung die jenseits der schmerzgrenze ist. das beispiel mit 23 jpgs hat ja schon 170 MB. Die Größenordnung von über 100 Bildern kannst Du dir dann sicher vorstellen. Das Ergebniss war ein Rechner der eine Reaktionzeit von ca 5 Minuten pro Eingabe hat und eine Auslagerungsdatei von einigen GB dank überfülltem RAM. Es muss doch Möglich sein die Dateien so wie Sie sind, im Beispiel also 9 MB, in den Arbeitsspeicher zu laden so das ich wie zB bei ACDSee eine Verzögerungsfreie Darstellung habe.


Muetze1 - Do 24.06.04 18:14

Moin!

Dann lade sie von Platte, da die paar kB zum laden nicht auffallen...

Ansonsten musst du bei ACDSee bedenken, das die Jungs optimiert haben ohne Ende...

MfG
Muetze1


DJ Raptor - Do 24.06.04 18:39

naja wie gesagt, wenn ich es von platte laden wollte hätte ich ja nicht hier gefragt. das funktioniert einwandfrei. aber die eine sekunde verzug die ich habe fürs laden ist mir schon zuviel. im prinzip ist es ein programm für professionelle fotostudios die bereits digital arbeiten. die profi kameras schicken die bilder digital als jpg oder tif per wireless lan an einen rechner. die software soll jetzt eben jedes neu ankommende bild erkennen und für das betrachten nach abschluss aller fotos die dateien im RAM cachen, um anschließend mit dem kunden eine auswahl zu treffen. klappt ja auch alles soweit aber die eine sekunde für das laden des bildes ist mir schon zuviel. das muss doch irgendwie machbar sein.


DJ Raptor - Do 24.06.04 18:42

naja wie gesagt, wenn ich es von platte laden wollte hätte ich ja nicht hier gefragt. das funktioniert einwandfrei. aber die eine sekunde verzug die ich habe fürs laden ist mir schon zuviel. im prinzip ist es ein programm für professionelle fotostudios die bereits digital arbeiten. die profi kameras schicken die bilder digital als jpg oder tif per wireless lan an einen rechner. die software soll jetzt eben jedes neu ankommende bild erkennen und für das betrachten nach abschluss aller fotos die dateien im RAM cachen, um anschließend mit dem kunden eine auswahl zu treffen. klappt ja auch alles soweit aber die eine sekunde für das laden des bildes ist mir schon zuviel. das muss doch irgendwie machbar sein.


Gausi - Do 24.06.04 19:08

Ne Idee: (So macht IMHO auch ACDSee das schnelle Anzeigen)
Wenn ein Bild geladen und angezeigt wurde, dann lade schon das nächste und pack es in den Speicher. Dieses kannst du dann bei dem entsprechenden Befehl "Zeige Nächstes Bild" fast ohne Verzögerung ausm Speicher laden und dann, während der User das Bild betrachtet, wieder das nächste laden...
Und für ne Übersicht über alle Bilder reichen ja wohl Thumbnails, also stark verkleinerte Versionen der Bilder. Diese musst du einmal erzeugen, und in einer Art Datenbank speichern, aus denen man diese dann schnell lesen kann...


Sven - Fr 25.06.04 07:21

Warum erzeugst Du nicht für jedes Bild einen Stream?. Dieser hat nach dem Laden nur die Größe, wie die Datei sie auf der Platte hatte. Die Daten sind dann gleich im Speicher und dann fällt das Dekomprimieren nicht auf.


DJ Raptor - Fr 25.06.04 09:31

das klingt nach einer guten alternative. hab leider noch nie mit streams gearbeitet. wie muss ich diesen denn erstellen bzw. abrufen?? Nachfolgend mal so wie es bisher funktioniert:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.listViewThumbsCacheItemAdd(
  Sender: TCustomVirtualExplorerListviewEx; NS: TNamespace;
  Thumbnail: TBitmap; var ImageWidth, ImageHeight: Integer;
  var DoDefault: Boolean);
  begin
    loadProgress.Visible := true;
    Application.ProcessMessages;
    if cfgCacheFiles.Checked = true then imageList.Bitmaps.Add.Bitmap.LoadFromFile(NS.NameForParsing);
    I:=I+1;
    loadProgress.Max := listView.TotalCount;
    loadProgress.Position := I;
    Label1.Caption:=inttostr(I)+'/'+inttostr(listView.TotalCount);
    if I = loadProgress.Max then loadProgress.Visible := false;
end;


Also entscheidend ist quasi Zeile 8. Wie muss ich hier den Code ändern um in einen Stream zu laden und wie kann ich nachher ein spezielles Bild wieder aus diesem laden?


MartinPb - Fr 25.06.04 10:35

Du kannst auch eine Objektliste machen und auf diese Weise eine unendliche menge Jpegs in sie laden. Leider hab ich gerade kein Delphi zur Hand und mir fällt der Name nicht ein. Ich glaube es heiß ObjectList oder ListObject oder so in der Art. Das ganze funktioniert in etwa wie StringList und AddObject, nur eben ohne String. Der Vorteil dabei ist, daß du direkt auf die Jpegs zugreifen könntest ohne sie vorher irgendwo zu laden oder extrahieren.


Muetze1 - Fr 25.06.04 10:45

Moin!

TObjectList

Grundlegend kann er anstatt der ImageList auch einfach 100 einzelne TImage's nehmen, das wird dann aber auf das gleiche hinauslaufen. Und nebenbei noch zu Resourcenknappheit bei den Windowsen ohne dynamische GDI Speicherverwaltung führen (Win9x, ME).

MfG
Muetze1


MartinPb - Fr 25.06.04 10:48

Ich hab mich wieder erinnert. Es ist TObjectList. Da ich aber gerade kein Delphi zur Verfügung habe kann ich dir kein Beispiel zaubern.


MartinPb - Fr 25.06.04 10:55

Muetze1 hat folgendes geschrieben:
das wird dann aber auf das gleiche hinauslaufen.


Auf das gleiche wie ImageList? Glaube ich nicht. ImageList arbeitet mit Bitmaps. ObjectList arbeitet nur mit einem Objekt. Dem ist egal ob es Bitmap, Jpeg oder sonstwas ist. Zumindest der Part des gigantischen Speicherverbrauchst wäre erledigt. Die Sache mit Ressourcen wäre was anderes. Könnte stimmen, aber es ist weniger sein Problem, als die des Betriebssystems.


DJ Raptor - Fr 25.06.04 11:04

hm also noch eine Möglichkeit. Was ist denn nun prinzipiell besser TObjectList oder Stream?? Und irgendwie bräucht ich dann jeweils ein Code Beispiel weil die Delphi Hilfe kann man diesbezüglich total vergessen. Also nochmal damit das Problem klar ist:

Ich benötige eine Möglichkeit Bilddateien in Ihrer Originalgröße in den Speicher zu laden um diese verzögerungsfrei anzeigen zu können.


Muetze1 - Fr 25.06.04 11:10

Moin!

MartinPb hat folgendes geschrieben:
Auf das gleiche wie ImageList? Glaube ich nicht. ImageList arbeitet mit Bitmaps. ObjectList arbeitet nur mit einem Objekt. Dem ist egal ob es Bitmap, Jpeg oder sonstwas ist. Zumindest der Part des gigantischen Speicherverbrauchst wäre erledigt.


Es geht nicht um die TObjectList sondern um TImage - und daher glaube ich nicht, das es sich mit dem Speicherverbrauch erledigt hat.

MfG
Muetze1


Gausi - Fr 25.06.04 11:56

Zitat:
Ich benötige eine Möglichkeit Bilddateien in Ihrer Originalgröße in den Speicher zu laden um diese verzögerungsfrei anzeigen zu können.

Du willst also die Bilder verzögerungsfrei anzeigen lassen. Aber wieso muss man dann ALLE Bilder in dem Ordner in den Speicher lesen? Das ist doch Quatsch.

Wenn ich das Bild "aaaa1.jpeg" anzeige, dann ist es doch nicht erforderlich, dass man dann auch das Bild "zzz9.jpg" schon im Speicher hat. Es reicht doch, wenn man nur das nächste, zu dem man per Tastendruck springen kann, im Speicher hat, oder nicht? Und das laden des jeweils nächsten Bildes kann erfolgen, während der User das gerade angezeigt studiert -> Keine Verzögerungszeiten, es sei denn, man macht ne Daumenkino-Slideshow mit 20 Bilder pro Sekunde...

Wenn ich ein Slide-Show Programm finde, was bei Programmstart oder Ordnerwechsel erstmal alle Bilder in den Speicher liest...dann schmeiß ich das wieder von der Platte runter. Ich möchte nämlich nicht 10 Sekunden warten, bis ich das Programm benutzen kann...


MartinPb - Fr 25.06.04 12:22

Muetze1 hat folgendes geschrieben:
Es geht nicht um die TObjectList sondern um TImage - und daher glaube ich nicht, das es sich mit dem Speicherverbrauch erledigt hat.


Wie kommst du überhaupt auf TImage? TImage ist eine visuelle Komponente. TImage für die Aufgabe zu nehmen ist im wahrsten Sinne mit Kanonen aus Spatzen schießen. Nein, er hat Jpegs und entweder sucht er sich (im Internet) eine Komponente alla TImageList für Jpegs, oder er nimmt TObejtList und legt dort seine Jpegs ab. Denn auch ein TJpeg ist ein Objekt.

@DJ Raptor

Ich hab gerade kein Delphi vor mir. Deshalb kann ich dir auch kein Beispiel liefern, weil ich mit TObjectList selbst noch nie was gemacht habe. Aber das dürfte kein großes Problem sein. Ob TObjectList oder TStringList, alle arbeiten ähnlich. Guck dir TObjectList selbst mal. Wahrscheinlich gibts da auch Beispiele.


DJ Raptor - Fr 25.06.04 12:34

es soll ja auch kein Programm für den normalen Heimanwender sein, sondern ein sehr fachbezogenes Programm für Fotostudios. Es soll ja während einer Fotosession nach und nach die Bilder in den Speicher laden so wie sie ankommen. und die Bilder sollen später dann alle miteinander verzögerungsfrei verglichen werden können. Ich guck ja keine Urlaubsfotos an wo ich von 1.jpg nach 2.jpg un so weiter wechsel, sondern ich möchte ohne Ladezeit 2.jpg mit beispielsweise 132.jpg vergleichen können und beliebig zwischen allen Bildern wechseln können.

Ich hab auch mittlerweile das ganze mit einem Stream lösen können. Allerdings kann dieser anscheinend keine Jpgs verwalten. Wenn ich ein Bitmap lade klappt das einwandfrei bei einem Jpg stürzt das Programm ab. Nachfolgend der momentane Code:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure TForm1.listViewThumbsCacheItemAdd(
  Sender: TCustomVirtualExplorerListviewEx; NS: TNamespace;
  Thumbnail: TBitmap; var ImageWidth, ImageHeight: Integer;
  var DoDefault: Boolean);
  var arrayLength: integer;
  begin
    loadProgress.Visible := true;
    Application.ProcessMessages;
    if cfgCacheFiles.Checked = true then
    begin

      arrayLength := length(stream);
      setLength(stream,arrayLength+1);
      stream[arrayLength] := TMemoryStream.Create;
      stream[arrayLength].LoadFromFile(NS.NameForParsing);

    end;
    I:=I+1;
    loadProgress.Max := listView.TotalCount;
    loadProgress.Position := I;
    Label1.Caption:=inttostr(I)+'/'+inttostr(listView.TotalCount);
    if I = loadProgress.Max then loadProgress.Visible := false;
end;


Geladen werden soll dann so:


Delphi-Quelltext
1:
  image.Bitmap.LoadFromStream(stream[0]);                    


MartinPb - Fr 25.06.04 12:57


Delphi-Quelltext
1:
image.Bitmap.LoadFromStream(stream[0]);                    


So kannst du auch keine Jpegs laden. Wenn, dann mußt du es über ein Umweg machen:



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
  Jpg: TJPEGImage;
begin
  Jpg := TJPEGImage.Create;
  try
    Jpg.LoadFromStream(...)
    ...


Und dann mit Assign an Image.Picture.Bitmap übergeben.

Allerdings finde ich immer noch, daß die TObjektList Variante besser wäre, da man da wunderbar auch die einzelnen Daten verwalten kann (anfügen, einfügen, löschen, ...).


DJ Raptor - Sa 26.06.04 12:56

Also zu TObjectList find ich nix bei Delphi in der Hilfe?? Weiß denn wer wie das funktionieren soll?


MartinPb - Sa 26.06.04 15:02

Welche Delphi Version hast du? TObjectList kamm erst irgendwann dazu.


DJ Raptor - Sa 26.06.04 17:09

also ich habe delphi 7 professional enterprise.


MartinPb - Sa 26.06.04 17:24

In der 7 ist TObjectList bereits drinn. Gib TObjectList nicht im Index, sondern in der Suche ein. Da kommst du zum Topic "Mit Listen arbeiten". Da findest du ein Link auf "TObjectList".


Codewalker - Mi 30.03.05 15:32

Ich hatte das Problem mit dem Speicherhunger auch. ich habe Bilder von meiner Digicam eingelesen und ab ca. 800 Bildern hat der einfach keine mehr angezeigt (zur Anzeige habe ich ein TListView benutzt). Ich habe dann einfach mal die tJvImageList aus der JEDI-VCL genommen. Die hat mehrere Modi von denen ich nicht genau sagen kann was sie bewirken, aber insgesamt ist der Speicherhunger bei mir je nach Bilder um bis zu 70% zurückgegangen.

Ein Versuch wäre es jedenfalls wert.

Mfg