![]() |
Änderung: PNG in 32bit Icon (alpha blended) wandeln
Hallo!
Ich habe einen Änderungsvorschlag für die folgende Methode: (orig. Artikel : PNG in 32bit Icon (alpha blended) wandeln (ohne GDI+) ![]() Die aktuelle Methode macht große Schwierigkeiten bei der Konvertierung von dem BitmapV5Header in die BitmapInfo. Bei der aktuellen Variante wird nicht der komplette Header übergeben sondern nur die ersten 44 Bytes. Das kann aus welchen Grund auch immer bei Delphi zufällig auftauchende, absolut irrsinnige Fehler erzeugen(Vergleichbar mit den Fehlern, wenn man über die Arraygrenzen hinausschreibt). Bei mir kam hin und wieder mal der Fehler "Division durch Null". Das lässt sich aber durch eine kleine Änderung beheben. (Getestet mit Delphi 2007 Ent.)
Delphi-Quellcode:
:cheers:
uses
Windows, [...] {Header mit BitmapV5Header} {$EXTERNALSYM CreateDIBSection} function CreateDIBSection(DC: HDC; const p2: TBitmapV5Header; p3: UINT; var p4: Pointer; p5: THandle; p6: DWORD): HBITMAP; stdcall; implementation function CreateDIBSection; external gdi32 name 'CreateDIBSection'; function PNGtoIcon(const APNG : TPNGObject; ACursor : Boolean = false; AHotSpotX : Integer = 0; AHotSpotY : Integer = 0) : HICON; var Width, Height : Integer; BitmapHeader : TBitmapV5Header; //TBitmapV5Header statt PBitmapV5Header hNewBitmap, hMonoBitmap : HBITMAP; Bits : Pointer; x, y : Integer; DC : HDC; IconInfo : _ICONINFO; Pixel : ^Integer; ScanLine : PRGBTriple; AlphaScanline : pByteArray; begin //Die Höhe und die Breite brauchen wir später noch ein paar Mal Width := APNG.Width; Height := APNG.Height; //So ein Icon hat einen "Bitmap Version 5 Header" //(Wichtig: Als Pointer, damit er später vom CreateDIBSection "genommen" wird) {*** New(BitmapHeader); Nicht mehr notwendig } //Die Größe der Struktur setzen, damit Windows weiß, "wie weit es gehen kann" :) BitmapHeader.bV5Size := sizeOf(BITMAPV5HEADER); BitmapHeader.bV5Width := Width; //Wichtig: negative Höhe angeben, sonst ist das Ergebniss an der X-Achse gespiegelt // ... bzw. der Ursprung des Bildes an der falschen Stelle (technisch richtiger) BitmapHeader.bV5Height := -Height; //Wir haben eine Ebene BitmapHeader.bV5Planes := 1; // ... und 32bit pro Bixel BitmapHeader.bV5BitCount := 32; //Das Bild wird nicht komprimiert BitmapHeader.bV5Compression := BI_BITFIELDS; //Und nun müssen wir noch sagen, wo sich die Farben und der Alpha-Wert innerhalb // ... der 32bit eines Pixels befinden BitmapHeader.bV5RedMask := $00FF0000; BitmapHeader.bV5GreenMask := $0000FF00; BitmapHeader.bV5BlueMask := $000000FF; BitmapHeader.bV5AlphaMask := $FF000000; DC := GetDC(0); //Ein neues Bitmap anlegen hNewBitmap := CreateDIBSection( DC, {*** Genau an dieser Stelle liegt die Ursache für das Problem... PBitmapInfo(BitmapHeader)^, //Hier ein wenig tricksen // ... damit der V5Header "reinpasst" } BitmapHeader, { Statt der alten Methode passt jetzt der komplette Header rein } DIB_RGB_COLORS, //wir haben RGB-Farben Bits, //eine Pointer auf das erste Pixel 0, //bedeutet, das wir das Bitmap im RAM haben wollen 0); // ... und deswegen brauchen wir auch kein Offset {*** Dispose(BitmapHeader); //der Header hat seine Schuldigkeit getan } ReleaseDC(0,dc); // ... und auch unser DC //man nehme ein Bitmap, welches wir später als Maske "verkaufen" hMonoBitmap:=CreateBitmap(Width,Height,1,1,nil); //Und los gehts beim ersten Pixel Pixel := Bits; for y := 0 to Height-1 do begin //aus dem PNG die Farbwerte einer Zeile holen ScanLine := APNG.Scanline[y]; // ... und dazu die Alpha-Werte AlphaScanline := APNG.AlphaScanline[y]; for x := 0 to Width - 1 do begin //ein Pixel-Wert setzt sich aus ... Pixel^ := AlphaScanLine[x]; // ... dem Alpha-Wert, ... Pixel^ := Pixel^ shl 8; Inc(Pixel^, Scanline^.rgbtRed); // ... einem Rot-Anteil, ... Pixel^ := Pixel^ shl 8; Inc(Pixel^, Scanline^.rgbtGreen); // ... einem Grün-Anteil, ... Pixel^ := Pixel^ shl 8; Inc(Pixel^, Scanline^.rgbtBlue); // ... und einem Blau-Anteil zusammen //weiter gehts mit dem nächsten Pixel innerhalb unseres RAM-Bitmaps Inc(Pixel); //und auch ein neues Pixel von unserem PNG währe nicht schlecht Inc(ScanLine); end; end; //Mit der IconInfo-Struktur können wir einige Eigenschaften des Icons setzen // ... z.B. ob es ein Cursor ... IconInfo.fIcon := not ACursor; if ACursor then begin // ... mit einem Hotspot ist IconInfo.xHotspot := AHotSpotX; IconInfo.yHotspot := AHotSpotY; end; //Aber auf jeden Fall brauchen wir ein Bitmap das als Maske dient IconInfo.hbmMask := hMonoBitmap; // ... und natürlich ein Bitmap mit dem eigentlichen Bild IconInfo.hbmColor := hNewBitmap; //Et voila ... ein schönes neues Icon Result := CreateIconIndirect(IconInfo); //natürlich räumen wir nachher auf DeleteObject(hNewBitmap); DeleteObject(hMonoBitmap); //Wichtig: Das Icon, das zurückgegeben wird muss auch mit DestroyIcon // ... freigegeben werden, wenn wir es nicht mehr brauchen. end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:31 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