![]() |
PNG zur Laufzeit in ImageList einfügen
Hallo,
diesmal möchte ich eine PNG Datei einlesen lassen und sie dann in eine ImageList einfügen.
Delphi-Quellcode:
Ich habe mir das jetzt irgendwie so gedacht, kriege aber leider immer eine Fehlermeldung, dass eine Speicherverletzung auftritt. Was genau fehlt mir noch bzw. was ist richtig an dem, was ich gemacht habe?
procedure build_imagelist(ImageList:TImageList);
var image : TBitmap; PNG : TPNGOBject; i :Integer; begin png.Create; image.create; png.LoadFromFile('images\bild1.png'); image.Assign(png); Imagelist.Add(image,nil); png.Destroy; image.Destroy; end; Gruß Micha PS nochmal danke für eure bisherige Hilfe. |
Re: PNG zur Laufzeit in ImageList einfügen
In welcher (Code-)Zeile?
|
Re: PNG zur Laufzeit in ImageList einfügen
Hallo,
in garkeiner Zeile. Compilieren und erzeugen passt beides. Aber beim Starten kommt dann folgende Meldung: Zugriffsverletzung bei Adresse {blabla} im Modul start.exe. Lesen von Adresse {blabla}. Ich lasse die Funktion übrigens bei onShow starten. Gruß Micha |
Re: PNG zur Laufzeit in ImageList einfügen
Delphi-Quellcode:
//falsch
png.Create; image.create; //richtig png := TPNGObject.Create; image := TBitmap.create; |
Re: PNG zur Laufzeit in ImageList einfügen
png := TPngObject.Create;
image := TBitmap.create; png.LoadFromFile('images\bild1.png'); image.Assign(png); Imagelist.Add(image,nil); png.Free; image.Free; |
Re: PNG zur Laufzeit in ImageList einfügen
Hallo,
dankeschön :-) Funktioniert. Und wie sorge ich dafür, dass die Hintergründe Transparent bleiben? Gruß Micha |
Re: PNG zur Laufzeit in ImageList einfügen
Zitat:
Zitat:
|
Re: PNG zur Laufzeit in ImageList einfügen
Liste der Anhänge anzeigen (Anzahl: 1)
Jetzt frag ich nochmal: Welche Delphi-Version hast du? (Das kannst du auch in deinem Profil eintragen damit es jeder sehen kann)
Ab Delphi 2009 (oder ab 2007?) unterstützt die IDE von Haus aus PNG-Bilder. Es sollte also auch eine Möglichkeit geben der ImageList ein PNG hinzu zufügen ohne es vorher in ein Bitmap oder ähnliches umzuwandeln. Da ich aber auch schon jede Menge Probleme mit der ImageList hatte, verwende ich nur noch die X²GraphicList (siehe Anhang). Da kann man alles rein laden 8-) |
AW: PNG zur Laufzeit in ImageList einfügen
Wir haben auf Delphi XE umgestellt. Leider habe ich das Problem der Transparenz von PNGs in Imagelisten.
Folgende Situation: PNGs sind in einer ImageDLL gespeichert: Auszug auf der rc Datei:
Delphi-Quellcode:
cut RCDATA "cut.png"
Um diese Dll habe ich eine Klasse geschrieben die die Bilder dann als TPngImage zurückgibt:
Delphi-Quellcode:
Das wird dann wiederum in eine TImagelist gespeichert:
function TImageDll.GetPNG(Name: string): TPngImage;
var hLib : THandle; begin try hLib := LoadLibrary(PChar(fImageDll)); Result := TPngImage.Create; Result.LoadFromResourceName(hLib, Name); except end; end;
Delphi-Quellcode:
ilStandard ist eine von mir erweiterte TImagelist, die zusätzlich beim Add ein GrayscaleImage in die Imagelist für die deaktivierten Bilder packt.
ilStandard.Add(sImageDll.GetPNG('cut'), nil);
Delphi-Quellcode:
Ich habe schon mit Transparenz hin und her probiert, aber nichts funktioniert.
function TMyImageList.Add(Image, Mask: TBitmap): Integer;
begin Result := inherited Add(Image, Mask); if Assigned(FDisabledImages) then begin ConvertColors(Image); if Assigned(Mask) then ConvertColors(Mask); FDisabledImages.Add(Image, Mask); end; end; Bisher habe ich die PNGs gleich in Bitmaps umgewandelt, aber dabei geht ja die Transparenz verloren. Ich habe mich da mit TransperentColor = clBtnFace beholfen, aber das sieht im Menü leider nicht so gut aus. Die Bilder werden in TMainMenu und in TControlBar benutzt. Die TToolButtons sehen dann gut aus, aber leider ist im Menü der Hintergrund nicht (immer) clBtnFace.
Delphi-Quellcode:
Ich hoffe ich hab mich verständlich ausgedrückt. Hier nochmal eine kurze Zusammenfassung was ich machen will:
function TImageDll.LoadPNG(Name: string; TransperentColor : TColor): Graphics.TBitmap;
var hLib : THandle; PNGImage : TPngImage; begin Result := Graphics.TBitmap.Create; try hLib := LoadLibrary(PChar(fImageDll)); PNGImage := TPngImage.Create; PNGImage.LoadFromResourceName(hLib, Name); PNGImage.Transparent := true; Result.Canvas.Brush.Color := TransperentColor; Result.Width := PNGImage.Width; Result.Height := PNGImage.Height; Result.Canvas.StretchDraw(Rect(0, 0, PNGImage.Width, PNGImage.Height), PNGImage); PNGImage.Free; except On E : EPNGCouldNotLoadResource do ShowMessageFmt(rcDLLFailure, [sDLLPath + rcImgDll]); end; end; 1. PNGs als Resource in eine DLL 2. PNGs mit LoadFromResourceName laden 3. PNGs in einer TImageList speichern UND dabei nicht den Alphachannel verlieren 3b. möglicherweise gleich GrayscaleImage erstellen und in eine zweite TImageList speichern 4. Bilder korrekt in TMainMenu, TToolButtons, ... anzeigen MIT richtigem Alphachannel Mein Knackpunkt ist Nummer 3. Vielen dank schon mal für die Antworten David P.S.: Uwes Vorschlag hat leider nicht geklappt. |
AW: PNG zur Laufzeit in ImageList einfügen
Ganz spontan geantwortet: delphis TImageList kennt keine derartige Transparenz (Alpha-Kanal), wie sie im PNG verbaut ist.
TImageList kennt nur RGB-Bitmap mit zusätzlichem Schwarz/Weiß-Masken-Bitmap (wür ein ICON also ein Bitmap mit den Farben und Nocheines mit einer Maske für die volltranzparenten Pixel) |
AW: PNG zur Laufzeit in ImageList einfügen
Im Downloadberech zu Delphi müsste es doch ein PNGImageListe geben? Damit bleibt semitransparenz erhalten.
Ansonsten schau dir mal die Kompos von LMD an. Dort gibt es auch eine PNG-Imageliste. |
AW: PNG zur Laufzeit in ImageList einfügen
Vielleicht macht die TPngImageList der
![]() |
AW: PNG zur Laufzeit in ImageList einfügen
Du kannst über einen umweg die PNG's mit GDI+ laden und zu TBitmap umwandeln
ohne den Alphachannel zu verlieren. Schau mal mein Sample GDIClock_v14 an.
Delphi-Quellcode:
var
hbmReturn : HBITMAP;
Delphi-Quellcode:
hbmReturn := LoadSourceImage('xxx.png'); if hbmReturn <> 0 then begin xxxImg := TBitmap.Create; xxxImg.Handle := hbmReturn; end;
Delphi-Quellcode:
gruss
// This function is used to load PNG file which has alpha channel and
// returns the handle to bitmap. // The rgbReserved element of bitmap gets the data of alpha channel. function LoadSourceImage(ImgFile : WideString) : HBITMAP; var img: cardinal; hbmReturn: HBITMAP; format : integer; begin Result := 0; if not GDIReady then exit; if not FileExists(ImgFile) then exit; GdipLoadImageFromFile(PWideChar(ImgFile), img); if img <> 0 then begin GdipGetImagePixelFormat(img, format); if format = PixelFormat32bppARGB then // Accept files with alpha channel begin GdipCreateHBITMAPFromBitmap(pointer(img), hbmReturn, $000000); if hbmReturn <> 0 then Result := hbmReturn; end; GdipDisposeImage(img); end; end; |
AW: PNG zur Laufzeit in ImageList einfügen
Danke erstmal an alle.
Ich habe es fast hinbekommen. Die TToolButtons haben nicht mehr hingehauen, aber das konnte ich mit dem TAdvDockPanel von TMS erschlagen. ABER Ich habe Text auf einige Bilder geschrieben:
Delphi-Quellcode:
Leider hat der bei einem PNG den Alphachannel vom Untergrund. Kann ich denn den Text direkt auf das PNGImage schreiben ohne den Umweg über den Canvas?
Image.Canvas.Brush.Style := bsClear;
Image.Canvas.Font. Name := 'Small Fonts'; Image.Canvas.Font. Size := 5; Image.Canvas.Font. Color := Color; Image.Canvas.TextOut(16 - Image.Canvas.TextWidth(Text), - 2, Text); Das wäre SUPER dann hab ich es genau so wie es es wollte. Danke David P.S.: es hat übrigens mit TPNGImageList geklappt. @EWeiss: sorry, aber eine weitere DLL an alle Benutzer ausliefern wollte ich dann doch nicht. |
AW: PNG zur Laufzeit in ImageList einfügen
:gruebel:
Ähm... Worin besteht das Problem? Wird einem Bitmap ein PNG-Bild zugewiesen, wird automatisch (falls vorhanden) die Transparenz übergeben und das Bitmap hat 32 Bit Farbtiefe (RGBA). Wird das Bitmap jetzt zur Image-Liste hinzugefügt, wird auch dabei die Transparenz berücksichtigt. Einzige Bedingung dabei: TImageList.ColorDepth muß auf cd32Bit stehen.
Delphi-Quellcode:
Weshalb also die ganzen Kopfstände mit GDI+, TPngImageList und Co.?
procedure TForm1.FormShow(Sender: TObject);
var Bmp: TBitmap; begin Bmp:=TBitmap.Create; try //Die Übergabe der Bilddaten erfolgt dabei von //TPNGImage.AssignTo(Bmp): Bmp.Assign(Image1.Picture.Graphic); //Die Maske ist egal, weil der Alpha-Kanal schon //im Bitmap enthalten ist: ImageList1.Add(Bmp,nil); finally Bmp.Free; end; end; P.S.: Text wird nun einmal ohne Hintergrund gerendert. Willst Du das nicht, setze
Delphi-Quellcode:
Canvas.TextFlags:=Canvas.TextFlags or ETO_OPAQUE;
//... |
AW: PNG zur Laufzeit in ImageList einfügen
Sicher daß TBitmap Transparenz kann?
Ich dachte das hätte im 32-Bit-Modus RGBP und nicht RGBA? (Red, Green, Blue, Palette/Alpha) |
AW: PNG zur Laufzeit in ImageList einfügen
Liste der Anhänge anzeigen (Anzahl: 1)
Ja, TBitmap unterstütz den Alpha-Kanal.
Ich hatte das vor einigen Tage getestet, als ich eigene Marker-Icons für Google Maps erstellen wollte. Anhang 33333 Gezeichnet wird dabei in ein TPNGImage, was für sich genommen noch nichts besonderes ist. Erst bei der Erstellung des Schattenbildes wird es interessant: Dabei wird das PNG-Bild als Maske samt Transparenz in ein Bitmap kopiert, perspektivisch verzerrt, gefiltert und wieder zurück in ein (neues) PNG-Image kopiert - und das alles unter Beibehaltung der Transparenz. |
AW: PNG zur Laufzeit in ImageList einfügen
Also ich hab folgendes probiert, aber geht noch nicht:
Delphi-Quellcode:
Lieder sehe ich noch keinen Text. Wenn ich TextOut dierekt auf Image mache, sehe ich nur dort Text wo im Ursprungsimage keine Transparenz vorhanden ist.
Image := TPngImage.Create;
Image.Transparent := true; Image := GetPNG('ABC'); if Image <> nil then begin if Color <> clNone then begin Image2 := TPngImage.CreateBlank(COLOR_GRAYSCALE, 1, 16, 16); Image2.Canvas.Brush.Style := bsClear; Image2.Canvas.Font. Name := 'Small Fonts'; Image2.Canvas.Font. Size := 5; Image2.Canvas.Font. Color := clBlack; Image2.Canvas.TextOut(16 - Image.Canvas.TextWidth(Text), - 2, Text); // HIER schreibe ich den Text ins Image2 for y := 0 to Image2.Height - 1 do begin for x := 0 to Image2.Width - 1 do begin // HIER wird der Text ins Image "kopiert" if Image2.Canvas.Pixels[x, y] = clBlack then Image.Pixels[x, y] := clBlack; end; end; end; end; with Image do begin for y := 0 to Height - 1 do begin pb := AlphaScanline[y]; for x := 0 to Width - 1 do begin ColorRGBToHLS(ImageColor, NewHue, NewLuminance, NewSaturation); // HIER soll der Text im Image nicht überschrieben werden if Pixels[x, y] <> clBlack then Pixels[x, y] := ColorHLSToRGB(NewHue, Trunc((pb^[x] + NewLuminance) / 2), NewSaturation); end; end; end; P.S.: ach so mit ColorHLSToRGB(NewHue, Trunc((pb^[x] + NewLuminance) / 2), NewSaturation); wird das PNG (hat nur den Alphachannel) in der "neuen" Farbe eingefärbt. |
AW: PNG zur Laufzeit in ImageList einfügen
@Thom: und das Ganze funktioniert auch noch mit TImageList?
|
AW: PNG zur Laufzeit in ImageList einfügen
Zitat:
Was für eine DLL? GDI+ ist auf allen Systemen enthalten. Zitat:
Zumindest meine Erfahrung. gruss |
AW: PNG zur Laufzeit in ImageList einfügen
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
Anhang 33334 Das rechte obere Smiley ist ein TImage mit dem Original-PNG-Bild. Im FormShow-Event wird dieses Bild in eine normale Image-Liste kopiert (siehe erstes Beispiel). Diese Image-Liste wird vom Button zur Darstellung des Icons genutzt (ohne jeglichen eigenen Quelltext). Das Quadrat unteren ist ein TShape-Objekt, das in seiner rechten oberen Ecke von einer kleinen PaintBox überlagert ist und in die mit
Delphi-Quellcode:
gezeichnet wird. Mehr ist das nicht: Keine Magie, keine Tricks...
procedure TForm1.PaintBox1Paint(Sender: TObject);
begin ImageList1.Draw(PaintBox1.Canvas,0,0,0); end; Eine Vergrößerung zeigt, das der Alpha-Kanal wirklich vorhanden ist: Anhang 33335 Zitat:
|
AW: PNG zur Laufzeit in ImageList einfügen
Ich möchte bezweifeln das der AlphaChannel korrekt angezeigt wird..
Schon mal den AlphaChannel auf 75% Durchsichtigkeit verändert und dann anzeigen lassen ? es sollte ja dann Transparent über deinen Panel liegen (Durchscheinend) So in der art .. Siehe Pic Hintergrundbild mit aufgesetztem PNG AlphaChannel 50% gruss |
AW: PNG zur Laufzeit in ImageList einfügen
Liste der Anhänge anzeigen (Anzahl: 1)
OK - Hier der Versuch mit Geister-Smileys:
Anhang 33337 Die Transparenz ist gut zu erkennen. Allerdings wird auch sichtbar, daß die Objekte (TImage und TButton) offenbar etwas unterschiedliche Zeichenalgorithmen verwenden, da die Farbsättigung differiert. P.S.: @EWeiss: Dein Bild sieht natürlich besser aus! 8-) |
AW: PNG zur Laufzeit in ImageList einfügen
Zitat:
Danke das du mich überzeugen konntest. Denke damit kann man leben :) Zitat:
hehehehe gruss |
AW: PNG zur Laufzeit in ImageList einfügen
Zitat:
P.S.: Dein Bild wird ja immer besser! 8-) Gefällt mir! |
AW: PNG zur Laufzeit in ImageList einfügen
Zitat:
Hab nochmal schnell nachgeguck: Zitat:
Delphi-Quellcode:
clSystemColor = $FF000000;
clNone = TColor($1FFFFFFF); clDefault = TColor($20000000); Genauso kann ich ja Binärdaten in einem (Ansi)String zwischenspeichern und es ist dennoch nicht sofort ein lesbarer/anzeigbarer "Text". |
AW: PNG zur Laufzeit in ImageList einfügen
Es geht :dp:
So um nur noch mein Ergebnis zu präsentieren: 1. Mit TImageList hat es NICHT geklappt. Was wohl auch an mir liegt. Ich hatte vergessen zu sagen das Bild selbst hat unterschiedliche Transparenz ich will das Bild nicht mit eine Gesamttransparenz zeichnen. Hier der Code mit dem es geht und unten dann die Erklärung dazu:
Delphi-Quellcode:
1.
if Image <> nil then
begin if Color <> clNone then begin Image2 := TPngImage.CreateBlank(COLOR_GRAYSCALE, 1, 16, 16); Image2.Canvas.Brush.Style := bsClear; Image2.Canvas.Font. Name := 'Small Fonts'; Image2.Canvas.Font. Size := 5; Image2.Canvas.Font. Color := clWhite; Image2.Canvas.TextFlags := Image2.Canvas.TextFlags or ETO_OPAQUE; Image2.Canvas.TextOut(16 - Image2.Canvas.TextWidth(Text), - 2, Text); end; end; with Image do begin for y := 0 to Height - 1 do begin pb := AlphaScanline[y]; for x := 0 to Width - 1 do begin ColorRGBToHLS(ImageColor, NewHue, NewLuminance, NewSaturation); if Image2.Pixels[x, y] = clWhite then begin Pixels[x, y] := clBlack; pb^[x] := 255; end else Pixels[x, y] := ColorHLSToRGB(NewHue, Trunc((pb^[x] + NewLuminance) / 2), NewSaturation); end; end; end; if Image <> nil then begin Liste.AddPng(Image); end;
Delphi-Quellcode:
erzeugt ein SCHWARZES Bild, ergo muß ich Weiß als Textfarbe nehmen.
TPngImage.CreateBlank(COLOR_GRAYSCALE, 1, 16, 16);
2.
Delphi-Quellcode:
Das ist der eigentliche Knackpunkt, hier muß ich den Alphachannel auch noch setzen.
if Image2.Pixels[x, y] = clWhite then
begin Pixels[x, y] := clBlack; pb^[x] := 255; end Vielen Dank an alle David |
AW: PNG zur Laufzeit in ImageList einfügen
Liste der Anhänge anzeigen (Anzahl: 2)
Sind hier nur Skeptiker unterwegs!? :wink:
Zitat:
Ich habe irgendwie den Eindruck, daß Du nach dem Motto gehts: Was nicht sein darf, das kann nicht sein. Probier's doch einfach aus: Lade ein beliebiges PNG-Bild in eine TImage-Komponente, kopiere zur Laufzeit das Bild in ein temporäres Bitmap und laß es in einer PaintBox anzeigen. Du wirst sehen: Die Transparenz des PNG-Bildes bleibt erhalten. Und jetzt kommt die (rhetorische) Frage: Wer hat das Bitmap auf den Bildschirm gezaubert? Das war Windows. Also kommt Windows (unter Berücksichtigung einiger Bedingungen) tatsächlich mit Alpha-Werten in Bitmaps zurecht! Damit Du's und alle anderen, die es nicht glauben (wollen/können) habe ich eine kleine Demo fertig gemacht: Anhang 33345 Der Kern des Ganzen:
Delphi-Quellcode:
Der Alpha-Kanal wird vom PNG-Bild korrekt in das Bitmap übernommen und von Windows wiederum richtig auf den Bildschirm dargestellt.
procedure TForm2.PaintBox1Paint(Sender: TObject);
var Bmp: TBitmap; begin Bmp:=TBitmap.Create; try Bmp.Assign(Image1.Picture.Graphic); PaintBox1.Canvas.Draw(0,0,Bmp); finally Bmp.Free; end; end; w.z.b.w. q.e.d. Sowohl die PaintBox als auch das Image sind auf dem Hintergrund verschiebbar. Wer's dann immer noch nicht glaubt, dem kann ich auch nicht mehr helfen... :roll: |
AW: PNG zur Laufzeit in ImageList einfügen
Zitat:
Aber in dem Fall schon ;) Dafür muss ich das nicht extra laden.. |
AW: PNG zur Laufzeit in ImageList einfügen
Etwas OT:
Zitat:
![]() ![]() Mal sehen, was himitsu dazu meint... (Damit meine ich nicht die Glaubensfrage sondern die Transparenzfähigkeit von Bitmaps.) :zwinker: |
AW: PNG zur Laufzeit in ImageList einfügen
Nur um es nochmal zum bekräftigen:
mit TImageList hat es nicht geklappt. Meine Schritte: 1. PNG in einer separaten DLL 2. mit TPngImage.LoadFromResourceName(hLib, Name); laden 3. mit ImageList.Add(Image, Mask); Bild speichern 4. Toolbuttons, Menüs die ImageList zuweisen und Bilder anzeigen lassen Das funktioniert leider so nicht, weil Punkt 3 den Alphakanal anscheinen schluckt. Also benutze ich die PNGComponents. Das hat PngImageList.AddPng(PngImage); und behält alles bei. Außerdem kann mit der PngImageList auch gleich die Disabled Version erzeugt werden. Dafür sind auch gleich PngSpeedButtons und PngBitButtons vorhanden. Es gibt noch ein/zwei Spezialfälle die ich hier auch noch erwähnen will. Eins der Bilder besteht nur aus dem Alphakanal und soll entsprechend eingefärbt werden. Danach werden in das Bild noch ein paar Buchstaben geschrieben. Ein paar Bilder werden aus der installierten Excel/Word Version extrahiert (Programmicons) und genauso das Notepadicon. Bei all diesen Funktionen mußte ich bei ImageList/TBitmap einem Trick anwenden. Die tranzparenten Teile des Bildes mußte ich mit clButtonFace einfärben. Das hatte jedoch unter anderem den Nachteil, das die Bilder im Menü immer diesen "Hintergrund" haben, auch wenn man drüber geht. @Thom: Wenn die Tranzparenz mit normalen ImageList/TBitmap funktioniert würde ich das sofort benutzen, aber ich habe es nicht hinbekommen. Wenn ich die Bilder zur Design-Time lade dann geht es, aber nicht zur Laufzeit. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:10 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-2025 by Thomas Breitkreuz