Einzelnen Beitrag anzeigen

Benutzerbild von chaosben
chaosben

Registriert seit: 27. Apr 2005
Ort: Görlitz
1.358 Beiträge
 
Delphi XE2 Professional
 

PNG in 32bit Icon (alpha blended) wandeln (ohne GDI+)

  Alt 27. Apr 2006, 18:19
Sinn:
-ein PNG-Bild in ein 32bit Icon mit Alphablending konvertieren und das Ganze ohne Nutzung von GDI+

Benötigte zusätzliche Units:
-PNGImage

Basierend auf:
-einem MSDN-Artikel

Delphi-Quellcode:
function PNGtoIcon(const APNG : TPNGObject;
                      ACursor : Boolean = false;
                      AHotSpotX : Integer = 0;
                      AHotSpotY : Integer = 0) : HICON;
var
  Width, Height : Integer;
  BitmapHeader : 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);

  //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,
                                PBitmapInfo(BitmapHeader)^, //Hier ein wenig tricksen
                                                            // ... damit der V5Header "reinpasst"
                                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;
[edit=Chakotay1308]SourceCode korrigiert. Mfg, Chakotay1308[/edit]
[edit=Chakotay1308]DeleteObject DestroyIcon. Mfg, Chakotay1308[/edit]
Benjamin Schwarze
If I have seen further it is by standing on the shoulders of Giants. (Isaac Newton)
  Mit Zitat antworten Zitat