Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Schnelleres laden von PNGs (https://www.delphipraxis.net/166989-schnelleres-laden-von-pngs.html)

pustekuchen 8. Mär 2012 15:11


Schnelleres laden von PNGs
 
Guten Tag,

ich habe hier ein Programm in dem oft und relativ viele PNG Dateien geladen werden und dannach in eine BMP umgewandelt wird. Da man dies an der Performence des Programms merkt, such ich nun eine bessere Lösung.
Ich habe bereits eine Alternativlösung versucht und zwar alle pngs die ich habe vorher in BMP umzuwandeln. Das Ergebnis war auch spürbar, jedoch steigt dann der benötigte Speicherplatz.

Der Quellcode sieht etwa so aus
Delphi-Quellcode:

TmpPng := TPngImage.Create;
for I := xMin to xMax do
begin
  for k := yMin to yMax do
  begin
    path := 'C:\'+IntToStr(x)+'\' +IntToStr(y) +'.png'
    TmpPng.LoadFromFile(path);
    FPicArray[i - xMin][k - yMin].Image := TBitmap.Create;
    FPicArray[i - xMin][k - yMin].Image.Assign(TmpPng);
  end;
end;
TmpPng.Free;
Was natürlich auch eine Möglichkeit wäre, ist das umwandeln zu optimieren.

Über Tipps und Hilfe bin ich sehr dankbar.

Gruß
pustekuchen

Neutral General 8. Mär 2012 15:17

AW: Schnelleres laden von PNGs
 
Naja, dass ist eben ein Naturgesetz beim Programmieren: Entweder dauerts länger oder es verbraucht mehr Speicher.

Es sind aber bei jedem Schleifendurchlauf andere Bilder ja?
Weil dein Beispielcode liese sich vereinfachen, wenn du das PNG vor der Schleife laden und konvertieren würdest.

pustekuchen 8. Mär 2012 15:23

AW: Schnelleres laden von PNGs
 
Ja die Bilder sind immer unterschiedlich.

Habe eine Zeile beigefügt, die dies verdeutlicht.

Popov 8. Mär 2012 15:23

AW: Schnelleres laden von PNGs
 
Gehe ich richtig davon aus, dass es ein Spiel ist? Half Life hat das Problem so gelöst in dem das Spiel an einem Punkt kurz stoppte, den Hinweis gab, dass gerade geladen wird und dann ging es weiter. Worauf ich hinaus will, was ist mit der goldenen Mitte? Den Teil konvertieren den man gerade braucht und den Rest nachladen.

pustekuchen 8. Mär 2012 15:29

AW: Schnelleres laden von PNGs
 
Nein es handelt sich nicht um ein Spiel. Es werden bereits nur die benötigten Daten geladen. Ingesamt sind es etwa 200.000 Bilder. Es wird nur ein Bruchteil dessen geladen. Jedoch kommt es öfter vor das diese Prozedur aufgerufen wird.

P.S. Ich hab nun Feierabend. Ich werde morgen antworten =)

Bernhard Geyer 8. Mär 2012 15:41

AW: Schnelleres laden von PNGs
 
Zitat:

Zitat von Popov (Beitrag 1155414)
Worauf ich hinaus will, was ist mit der goldenen Mitte? Den Teil konvertieren den man gerade braucht und den Rest nachladen.

Dann mach es halt so. Dein Array wird eine Klasse. Beim Zugriff auf bestimmte ID schaust du nach ob sie schon geladen ist und lädst sie wenn nicht.

Klaus01 8. Mär 2012 16:10

AW: Schnelleres laden von PNGs
 
.. wenn ein bestimmtes Bild geladen/angefordert wurde ist es Dir dann möglich
vorrauszusehen welche(s) Bild/Bilder als nächstes angefragt werden könnten.
Wenn dem so ist, könntest Du einen Thread mit dem Nachladen beschäftigen.

Grüße
Klaus

Bernhard Geyer 8. Mär 2012 16:15

AW: Schnelleres laden von PNGs
 
Zitat:

Zitat von Klaus01 (Beitrag 1155429)
.. wenn ein bestimmtes Bild geladen/angefordert wurde ist es Dir dann möglich
vorrauszusehen welche(s) Bild/Bilder als nächstes angefragt werden könnten.
Wenn dem so ist, könntest Du einen Thread mit dem Nachladen beschäftigen.

Und hoffen das es nicht kracht. TBitmap verwendet ja ein GDI-Ressourcen und diese sind nur für den Thread gültig indem sei erzeugt wurden.



@pustekuchen: Wieso Arbeitest du nicht durchgehend mit PNG's? Haben ja mit der Semitransparenz einen großen Vorteil gegenübr PNG's.

Klaus01 8. Mär 2012 16:25

AW: Schnelleres laden von PNGs
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1155432)
Zitat:

Zitat von Klaus01 (Beitrag 1155429)
.. wenn ein bestimmtes Bild geladen/angefordert wurde ist es Dir dann möglich
vorrauszusehen welche(s) Bild/Bilder als nächstes angefragt werden könnten.
Wenn dem so ist, könntest Du einen Thread mit dem Nachladen beschäftigen.

Und hoffen das es nicht kracht. TBitmap verwendet ja ein GDI-Ressourcen und diese sind nur für den Thread gültig indem sei erzeugt wurden.

O.k, dass war mich nicht so bewusst.

Dann im Thread PNG nach BMP wandeln (das BMP im Thread behalten) und den Inhalt des BMP als MemoryStream an das Hauptprogramm übergeben und dort wieder in ein Bitmap einkopieren.

Grüße
Klaus

Iwo Asnet 8. Mär 2012 18:01

AW: Schnelleres laden von PNGs
 
Verwende einen Cache, genauer gesagt, einen MRU-Cache. "Most Recently Used". Klingt toll, ist banal:
Du baust Dir eine Liste (verkettet z.B.) mit maximal N Elementen, oder sovielen Elementen, das maximal X Bytes Speicher verbraucht werden.
Die ist zunächst leer.

bevor Du eine PNG in eine Bitmap konvertieren willst, schaust Du im Cache nach, ob die da drin ist. Wenn ja, kommt sie an den ANFANG der Liste. Wenn nicht, wird sie erzeugt und auch an den ANFANG gepackt. Dadurch wächst die Liste. Wenn sie zu groß ist (mehr als N Elemente oder mehr als X Bytes Speicher) wird der LETZTE Eintrag der Liste verworfen.

3-2-1- Perfekt, skalierbar, schnell.

Das tolle ist ja, das die tendentiell oft benötigten Objekte vorne sind, und die selten benötigten eben tendentiell hinten. Also wird ein Cache-Miss relativ selten sein.

Breager 9. Mär 2012 06:32

AW: Schnelleres laden von PNGs
 
Immer dieses Rätselraten :wink:
Je genauer Du beschreibst, was Du eigentlich vorhast, desto wahrscheinlicher ist, dass Dir jemand helfen kann. Oder ist das ein Geheimnis?

Je nach der Größe einzelner Bilder ist es sinnvoll, diese zu einem großen Bild (Tilemap) zusammenzufassen, das große Bild zu laden und anschließend den entsprechenden Bildausschnitt zu kopieren. Wie werden die einzelnen Bilder angezeigt? In verschiedenen Image-Komponenten oder in einer? Werden die Bilder zufällig ausgewählt, oder ist es absehbar, welche Bilder verwendet werden?

pustekuchen 9. Mär 2012 06:44

AW: Schnelleres laden von PNGs
 
Vielen Dank für die Zahlreichen antworten =)

Zitat:

Zitat von Klaus01 (Beitrag 1155429)
.. wenn ein bestimmtes Bild geladen/angefordert wurde ist es Dir dann möglich
vorrauszusehen welche(s) Bild/Bilder als nächstes angefragt werden könnten.

Ja wäre es.

Zitat:

Zitat von Klaus01 (Beitrag 1155429)
@pustekuchen: Wieso Arbeitest du nicht durchgehend mit PNG's? Haben ja mit der Semitransparenz einen großen Vorteil gegenübr PNG's.

Gut das du mich darauf nochmal aufmerksam machst. Wenn ich mich recht entsinne habe ich es so gemacht, weil ich die PNG nach BMP umwandle, diese einzelteile dann auf eine große Bitmap kopiere und dann einen Teilbereich auf eine Paintbox zeichne. Da gab nachher das Problem, das die Bilder unterschiedliche Farben hatten und das Endergebniss dann ein zusammenengewürfeltes Kunderbunt war. Wenn ich natürlich nun richtig die PNG auf die große Bitmap gezeichnet bekommen, wäre das schonmal ein großer Performance schub.

EDIT: Habs nun nochmal umgeschrieben.
Delphi-Quellcode:
if not Assigned(FPicArray[i - xMin][k - yMin].PngImage) then
          begin
            FPicArray[i - xMin][k - yMin].PngImage := TPNGImage.Create;
            FPicArray[i - xMin][k - yMin].PngImage.Transparent := false;
          end;
          FPicArray[i - xMin][k - yMin].PngImage.LoadFromFile(Path);
Dannach wird das ganze folgendermaßen Kopiert.
Delphi-Quellcode:
BitBlt(Map.Canvas.Handle, xCount, yCount, SIZE_TILE, SIZE_TILE,
            FPicArray[i][k].PngImage.Canvas.Handle, 0, 0, SRCCOPY);
Nun kommen wieder die Kunterbunten Bilder, die dann etwa so aussehen:
Klick

EDIT2: Selbe Problem

Zitat:

Zitat von Iwo Asnet (Beitrag 1155456)
Verwende einen Cache, genauer gesagt, einen MRU-Cache. "Most Recently Used". Klingt toll, ist banal:
Du baust Dir eine Liste (verkettet z.B.) mit maximal N Elementen, oder sovielen Elementen, das maximal X Bytes Speicher verbraucht werden.
Die ist zunächst leer.

bevor Du eine PNG in eine Bitmap konvertieren willst, schaust Du im Cache nach, ob die da drin ist. Wenn ja, kommt sie an den ANFANG der Liste. Wenn nicht, wird sie erzeugt und auch an den ANFANG gepackt. Dadurch wächst die Liste. Wenn sie zu groß ist (mehr als N Elemente oder mehr als X Bytes Speicher) wird der LETZTE Eintrag der Liste verworfen.

3-2-1- Perfekt, skalierbar, schnell.

Das tolle ist ja, das die tendentiell oft benötigten Objekte vorne sind, und die selten benötigten eben tendentiell hinten. Also wird ein Cache-Miss relativ selten sein.

Das ist natürlich auch eine sehr gute Idee und würde im meinem Fall wahrscheinlich auch ein wenig helfen und dies werde ich dann auch noch implementieren.
Jedoch ist es ehr so das beim Laden der Bilder am meisten performance verloren geht und dies zuerst optimiert werden sollte.


Zitat:

Zitat von Breager (Beitrag 1155528)
Immer dieses Rätselraten :wink:
Je genauer Du beschreibst, was Du eigentlich vorhast, desto wahrscheinlicher ist, dass Dir jemand helfen kann. Oder ist das ein Geheimnis?

Je nach der Größe einzelner Bilder ist es sinnvoll, diese zu einem großen Bild (Tilemap) zusammenzufassen, das große Bild zu laden und anschließend den entsprechenden Bildausschnitt zu kopieren. Wie werden die einzelnen Bilder angezeigt? In verschiedenen Image-Komponenten oder in einer? Werden die Bilder zufällig ausgewählt, oder ist es absehbar, welche Bilder verwendet werden?

Ja hast schon recht =) Es stelle mit meiner Anwendung eine Karte dar, die aus Tiles besteht. Das zusammenkopieren auf eine Karte und dann einen Bildauschnitt rauszukopieren passiert bereits.

Edit: Das Kopieren geschieht mit BitBlt

Uwe Raabe 9. Mär 2012 07:49

AW: Schnelleres laden von PNGs
 
Mangels realen Daten kann ich es nicht ausprobieren, aber ich würde versuchen, die PNGs direkt zu speichern und mit TPngImage.Draw an die passende Stelle zu zeichnen.

pustekuchen 9. Mär 2012 08:16

AW: Schnelleres laden von PNGs
 
Die Draw Methode ist aber leider nicht so performant wie BitBlt und in diesem Fall, bei dem oft gezeichnet wird, ist es nicht ausreichend.

Furtbichler 9. Mär 2012 20:28

AW: Schnelleres laden von PNGs
 
Ermittle die Anzahl der CPUs und erstelle entsprechende Threads, die das Einladen erledigen.

Bummi 9. Mär 2012 22:00

AW: Schnelleres laden von PNGs
 
Zitat:

Die Draw Methode ist aber leider nicht so performant wie BitBlt und in diesem Fall, bei dem oft gezeichnet wird, ist es nicht ausreichend.
Ich würde ohnehin nicht in ein Zielbitmap malen sondern im (On)Paint eines GraphicControls (oder auch einer Paintbox) mit den GDI+ Routinen arbeiten, diese unterstützen nativ 32-Bit und Transparenzen.
http://www.progdigy.com/?page_id=7

2 Units einbinden, nichts installieren ...

lbccaleb 10. Mär 2012 14:03

AW: Schnelleres laden von PNGs
 
Vllt. hilft dir auch diese Komponente weiter.

Edit:
An deiner Stelle würde ich die Images gar nicht umwandeln, sondern so mit den PNG´s weiter arbeiten....

Thom 10. Mär 2012 22:17

AW: Schnelleres laden von PNGs
 
Zitat:

Zitat von pustekuchen (Beitrag 1155417)
Ingesamt sind es etwa 200.000 Bilder.

Zitat:

Zitat von pustekuchen (Beitrag 1155532)
Ja hast schon recht =) Es stelle mit meiner Anwendung eine Karte dar, die aus Tiles besteht. Das zusammenkopieren auf eine Karte und dann einen Bildauschnitt rauszukopieren passiert bereits.

:gruebel:
Ich gehe mal davon aus, daß die Kartenteile auf legalem Weg erstanden wurden und will an dieser Stelle nicht den moralischen Zeigefinger erheben.

Dann bietet sich aber auf jeden Fall die Verwendung eines JavaScript-Viewers in Verbindung mit dem WebBrowser an (Google Maps, OpenLayers, ...). Alle diese Lösungen unterstützen auch die Anzeige beliebiger, anwenderdefinierter Bilder. Sie sind zugegebenermaßen nicht die schnellsten (meine reine Delphi-Lösung ist locker um den Faktor 10 schneller), sind aber auch mit relativ geringem Aufwand nutzbar. Willst Du ein ausgereiftes Programm in reinem Delphi - zum Beispiel mit kontinuierlichem Zoom, animierter Verschiebung der Karte per Maus, Overlays (unter transparente PNG's muß auch etwas darunter) und Steuerelemente -, kannst Du einen Entwicklungsaufwand von etlichen Monaten einplanen. Daraus ergeben sich schnell Kosten im 5-stelligen Bereich, wenn's nicht nur aus Spaß an der Freude geschehen soll.

Wenn Geld eine untergeordnete Rolle spielt, könntest Du eventuell die Komponente TGAgisSmartMap verwenden. Die ist in der Lage - soweit man das der compilierten Demo entnehmen kann - Tiles von der Festplatte anzuzeigen. Der Anbieter läßt sich das aber recht gut bezahlen: Für das Basic Package werden 499 und für das Standard Package 699 US-Dollar + MwSt. fällig - und das ohne Quelltext! Die werden schon wissen, weshalb... :lol:

Dann ist natürlich noch ausschlaggebend, ob deine Lösung plattformübergreifend - also zum Beispiel auch mit FireMonkey - funktionieren soll. Ansonsten würde ich auch die Verwendung von Graphics32 in Verbindung mit Threads als optimale Lösung empfehlen.

Wenn Du das allerdings schon so weit hast, würde ich mich sehr für Deine Lösung interessieren...

Bummi 10. Mär 2012 22:37

AW: Schnelleres laden von PNGs
 
@Thom
mit WorldTranslation/Transformation ist das ganze doch zu 80% abgefackelt bei quasi keinem Aufwand.

Thom 10. Mär 2012 23:44

AW: Schnelleres laden von PNGs
 
@Bummi

Leider nicht wirklich. Jede Zoomstufe erfordert neue Kacheln, da ja sonst auch alle grafischen Details (Schrift, Straßen usw.) vergrößert bzw. verkleinert werden. Hast Du ganz weit herausgezoomt, bräuchtest Du zum Lesen ein Mikroskop - ansonsten hast Du Text für (fast) Blinde... :cyclops:
Dann geht es weiter mit der Verwaltung der Kacheln. Normalerweise kannst Du die Karte horizontal beliebig verschieben (also Dich quasi 199 mal um den Globus drehen) - vertikal ist aber bei rund 80° Schluß. Wurde jetzt eine Karte mit niedriger Zoomstufe x mal um 360° verschoben und anschließend kräftig hineingezoomt, entstehen leicht Zahlen, die schon an die Grenzen von Int64 gehen. Also muß bei der gesamten Koordinatentransformation extrem aufgepaßt werden, damit es zu keinen Überläufen kommt. Bei Zoomstufe 22 handelt es sich um Terrapixelbilder - nur eben in kleine Teile zerlegt.
Will man sogar eine animierte Verschiebung der Karte (wie das Wischen auf einem Touchscreen) kommt man schnell in die Verlegenheit, auch noch mit Gleitkommazahlen rechnen zu müssen. Das überfordert dann alle Standardtypen und man muß eigene Typen und Berechnungen dazu entwerfen.
Die Kacheln müssen asynchron geladen und angezeigt werden. Das bedeutet Threads in Verbindung mit GDI...
Das geht alles, ist auch machbar - aber leider nicht "eben mal so nebenbei". :roll:

Bummi 11. Mär 2012 07:31

AW: Schnelleres laden von PNGs
 
Die GDI+ arbeiten standardmäßig mit Doubles.
Was ich nicht bedacht habe sind die von Dir erwähnten Details (Beschriftungen etc), hierbei stellt sich für mich allerdings die Frage ob diese nicht im Vektorformat "darübergelegt" werden sollten.
Aber Du hast recht, ich hatte nicht verstanden dass es sich um etwas wie Google-Earth handeln soll, ich hatte eher die Welt eines Spiels vor den Augen.

Thom 11. Mär 2012 10:11

AW: Schnelleres laden von PNGs
 
@Bummi

Ich weiß ja nicht, woher er seine Bilder hat - aber normalerweise sind alle Beschriftungen usw. als jpg- bzw. png-Bild vorgerendert. Etwas anderes wäre es, wenn die Kacheln in einem echten Vektorformat, wie zum Beispiel svg, vorliegen würden. Wer ganz viel Zeit und/oder Geld hat, kann sich die Karten auf Basis des OpenStreetMap-Projektes auch selbst rendern. Das geht alles - ist eben nur eine Frage des Aufwandes, den man treiben will. Irgendwo - ich glaube, es war bei YouTube - hatte ich auch einmal ein Lösung gesehen, bei der die Geodaten mit DirectX beziehungsweise OpenGL gerendert wurden... :lol:
Ich habe übrigens zur Koordinatentransformation den Typ Extended verwendet.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz