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.
von Stackoverflow
Delphi-Quellcode:
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;
Die
PNGComponents von Uwe Raabe habe ich kurz danach auch gefunden, die Funktion SlicePNG ist ja recht ähnlich dazu. Die würde ich grade auch bevorzugen - zuerst Slicen und für jede Auflösungsstufe die PNG-Listen erstellen lassen und die dann in die ImageCollection schaufeln.
Frage am Rande: Kann ich die mit Quellenangabe in mein OpenSource-Projekt übernehmen? Finde da keine Lizenzangabe...
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?
The angels have the phone box.