![]() |
PNG in mehrere Teile aufteilen
Zuerst dachte ich, das ginge ganz einfach. Dann habe ich ChatGPT gefragt, und das hat rumhalluziniert und dabei den Knackpunkt gewissenhaft ignoriert. Und weil ich weiß, dass hier ein paar PNG-Experten unterwegs sind, frage ich lieber hier mal nach. :)
Mit Blick auf Unterstützung für Skalierung möchte ich zur Laufzeit ein paar ImageCollections füllen, die dann wie üblich VirtualImageListen als Quelle dienen. Der Plan ist (um die Anzahl der Dateien klein zu halten), dass alle Icons für eine VirtualImageList in einer Datei liegen (bzw. je eine Datei für 100%, 125%, 150%, ...). Zur Laufzeit soll diese große PNG-Datei dann häppchenweise in die ImageCollection eingefügt werden - inklusive Transparenz und Alphakanal. Und da erscheint mir der Code, den ich mir zusammengesucht habe, etwas umständlich. Direkt eincompilieren (gefüllte ImageCollection auf einem DataModul etc) möchte ich die Bilddaten nicht, da ich mehrere Icon-Sets zur Auswahl mitliefern möchte, die erst zur Laufzeit geladen werden sollen - und die ggf. auch vom Anwender ergänzt werden können. Quelle u.a. ![]()
Delphi-Quellcode:
Die
procedure LoadImagesFromPNG(const AFileName: string; AImageCollection: TImageCollection;
AImageSize: Integer); var SourcePng, singleIconPNG: TPngImage; i, Count: Integer; Item: TImageCollectionItem; newImageCollectionItem : TImageCollectionSourceItem; SrcRect: TRect; srcAlphaArray: pByteArray; destAlphaArray: pByteArray; X, Y, xOffset, yOffset: Integer; begin SourcePng := TPngImage.Create; try SourcePng.LoadFromFile(AFileName); Count := SourcePng.Width div AImageSize; for i := 0 to Count - 1 do begin yOffset := 0; xOffset := i * aImageSize; SrcRect := Rect(i * AImageSize, 0, (i + 1) * AImageSize, AImageSize); singleIconPNG := TPNGImage.CreateBlank(COLOR_RGBALPHA, 8, AImageSize, AImageSize); try singleIconPNG.CreateAlpha; singleIconPNG.Canvas.CopyMode := cmSrcCopy; singleIconPNG.Canvas.CopyRect(Rect(0, 0, AImageSize, AImageSize), SourcePng.Canvas, SrcRect); if SourcePng.TransparencyMode = ptmPartial then begin // Update destination png with tranparency data from original for Y := 0 to SourcePng.Height - 1 do begin srcAlphaArray := SourcePng.AlphaScanline[Y]; destAlphaArray := singleIconPNG.AlphaScanline[Y + YOffset]; for X := 0 to SourcePng.Width - 1 do destAlphaArray^[X] := srcAlphaArray^[X + XOffset]; end; end; // Testweise als einzelnes PNG speichern singleIconPNG.SaveToFile(AFilename + i.ToString + '.png'); // Neues Item in der ImageCollection hinzufügen // Code von ChatGPT, dass muss natürlich noch angepasst werden für mehrere Auflösungen Item := AImageCollection.Images.Add; Item.Name := Format('%s_%d', [ExtractFileName(AFileName), i]); newImageCollectionItem := Item.SourceImages.Add; newImageCollectionItem.Image.Assign(singleIconPNG); finally singleIconPNG.Free; end; end; finally SourcePng.Free; end; end; ![]() Mein "Problem" ist nun, ob sich der Aufwand dann überhaupt noch "lohnt". Meine Hoffnung ist, dass das Laden einer Datei und Aufteilen in kleinere Grafiken schneller geht als das Laden von vielen einzelnen Dateien. Bei dem Code bin ich mir da aber nicht mehr so sicher. Es geht dabei um ca. 100 Icons (aufgeteilt in 3 Gruppen), die ich in 4 oder 5 Auflösungen anbieten möchte (Für 100-200% Skalierung). Also ~500 Dateien einzeln laden vs. ~5 (bzw. 15) Dateien laden und splitten. Hat jemand in der Hinsicht Erfahrungswerte oder kann eine kompetente Schätzung abgeben, was sinnvoller wäre? :gruebel: |
AW: PNG in mehrere Teile aufteilen
Zitat:
Ich sollte die Lizenz vielleicht mal in meinem Repo nachziehen... |
AW: PNG in mehrere Teile aufteilen
Zitat:
Wie wäre es, wenn du die Dateien selbst in eine Datei packst, so dass du die dann als MMF laden und dann direkt aus dem Arbeitsspeicher arbeiten kannst? Dafür kannst du z.B. auch Delphis TZipFile nehmen. Dann fällt das Lesen vieler Dateien von der Festplatte weg (was aber bei SSDs weniger von Bedeutung ist als früher). Wie lange dauert das denn aktuell? |
AW: PNG in mehrere Teile aufteilen
Zitat:
Für den Anwender wäre es auch viel leichter eine neue Datei mit einem sprechenden Dateinamen an eine passende Stelle zu legen und diesen als Referenz zu verwenden. Das könnte man vermutlich leichter realisieren, als eine potenziell fehleranfällige Manipulation der Iconset-Dateien. Außerdem, was machst du mit einer vom Anwender erweiterten Icon-Set-Datei, wenn du beim nächsten Release selbst neue Icons dazufügen willst? Ich würde diesen One-File-Ansatz ohne zwingende Gründe eher nicht verfolgen. Mit
Delphi-Quellcode:
hat man auch einen einfachen Mechanismus mehrere unterschiedlich große Icons unter demselben Namen in die Collection einzulesen. Der ganze Aufwand beim Zusammensetzen der großen Images und das anschließende zerpflücken wär mir das nicht wert.
TImageCollection.Add(AName: String; const AFileName: String);
|
AW: PNG in mehrere Teile aufteilen
Danke schonmal für die Antworten. :-D
Zitat:
Zitat:
Aber die Einwände sind nachvollziehbar, und die teile ich ja auch (daher auch das Topic). Diese Scanline-Orgie und mehrfaches rum-assignen scheint dafür eher eine Sackgasse zu sein. Ich werde dann vermutlich erstmal den Multifile-Ansatz verfolgen und versuchen, da ein überschaubares System für die Dateinamen hinzubekommen. Ggf. reduziere ich auch den Aufwand beim Start, indem ich erstmal nur die benötigte Skalierungsstufe in die Collection lade, und bei einem Wechsel ggf. nachlade. Das sollte ja auch möglich sein. |
AW: PNG in mehrere Teile aufteilen
Zitat:
|
AW: PNG in mehrere Teile aufteilen
Ja, irgendwo werden da auch Unterordner eine Rolle spielen. Alles direkt ins Stammverzeichnis ist dann doch ein wenig unübersichtlich. :lol:
Das muss aber in einem vernünftigen Maß geschehen, da ja auch (wahrscheinlich) schon ein Unterordner für jede Skalierungsstufe gebraucht wird. Ob ich dann alle Grafiken (also für die Menüs, Buttons, Hintergrundgrafiken, Grafiken in den Treeviews und Listen, ..) in einen Ordner packe, oder da auch noch Unterverzeichnisse nutze, muss ich mal sehen. Der geplante Umbau zieht ja auch noch einige weitere Dinge nach sich. Die Verwendung von ImageName statt ImageIndex hat ja durchaus Vorteile (erfordert aber einiges an Refactoring im bestehenden Code). Und es wäre bestimmt auch mal sinnvoll, fürs Hauptmenü und die diversen Kontextmenüs dieses neumodische Zeugs "ActionList" zu verwenden. Das ist nämlich auch noch so eine Altlast, dass ich dieses Konzept bisher nicht verwende. Aber wie gesagt, ich bin da in der Vorbereitungsphase. Das hier ist ein Punkt, den ich dann vermutlich lieber bleiben lasse bzw. den bisherigen Code rausschmeiße, der dieses auseinanderfrickeln mit Bitmaps ohne Alphatransparenzen macht. Bei 16x16 Icons für das 100%-Menü ist das noch ok, bei höheren Skalierungen sieht das aber doch irgendwann blöd aus. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz