![]() |
TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Mahlzeit
Ich hab ein TBitmap aus einem Icon rausgezogen, nur leider liegt die ColorMask eines Icons nicht so vor wie ich möchte. Und zwar ist bei diesem Bitmap das PixelFormat pfDevice, was ja auch eigentlich alles sein könnte. Wenn ich das PixelFormat auf 32bit setze, hab ich dann ja auch 32bit Information in dieser Bitmap wie Alpha Channel z.B. Nur manchmal ist so ein Bitmap eben nicht im 32bit Modus sondern z.b. nur 8 oder 16bit, nur das Pixelformat bleibt gleich beim TBitmap, nämlich pfDevice. Wie kann ich nun rauskriegen ob die Bitmap die ich bearbeite im 32bit Modus ist oder nicht, allerdings ohne das ich mich auf TBitmap.Pixelformat stützen muss ? Schon mal Danke im Vorraus. - Thebe |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Sooo... *schieb*
Ich hab nun herausgefunden das ich da mit dem FormatDescriptor vom Bitmap was anfangen kann. Und zwar:
Delphi-Quellcode:
Es funkt tatsächlich, nur es gibt ein riesen Manko bei dem Teil:
var
pfd: PixelFormatDescriptor begin DescribePixelFormat(result.Canvas.Handle, GetPixelFormat(result.Canvas.Handle), sizeof(PixelFormatDescriptor), pfd); if pfd.iPixelType = PFD_TYPE_RGBA then ShowMessage('Es ist 32BIT!'); end; Um ca. 6 Bitmaps damit abzuchecken, braucht mein Rechner (P4 2,6Ghz, 1G Ram, WinXP) ma so locker 2-3 Sekunden. Und das ist mir zuviel, besonders da ich die Funktion benutzen will wo auch mal 20 Bitmaps abgecheckt werden müssen. Dann sitzt der Benutzer 7-10 Sekunden doof rum, was ich absolut nicht befürworten kann. Habt ihr ne Ahnung wie ich diese langsame Funktion (DescribePixelFormat, GetPixelFormat) durch andere ersetzen kann ?? - Thebe |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Ich muss leider den Thread wieder aussem Grab heraus befördern, weil ich immer noch in dieser Hinsicht Probleme hab. Am besten beschreibe ich mal alles haargenau was ich mache, vielleicht kann man dann besser das Problem nachvollziehen.
Also: Ich möchte Icons in eine 32bit Bitmap umwandeln und je nachdem ob ich ein neues XP Icon oder ein altes Icon mit 24bit Farbe umwandle, muss ich da anders ran. Jedes Icon hat ja einmal eine BMP, in der die Farbinformationen (und bei XP Icons, der Alphakanal) enthalten ist. Dann hat das Ding eine Maskierungs BMP, in der (auch bei XP Icons, zwecks Kompatibilitätsgründen schätz ich ma) eine 1bit Maskierung abgespeichert is, die bestimmt welcher Pixel vom Icon durchsichtig is und welcher nicht. Wenn ich also ein XP Icon umwandeln möchte, dann ist die BMP mit dem Farbinformationen eine 32bit Bitmap, in der auch der Alphakanal drinne ist, sprich ich muss einfach nur diese BMP weiterverwenden und gut ist. Wenn ich nun aber ein altes Icon umwandle, dann is die BMP mit den Farbinformationen nur max. 24bit, sprich ich muss die BMP mit dem Farbinformationen zu 32bit umwandeln und dort selbstständig den Alphakanal reinspeichern, der sich aus der Maskierungs Bitmap ergibt. Problem: Ich benutze bei den Bitmaps die Klasse TBitmap. Deren Eigenschaft PixelFormat ist leider vom Typ pfDevice (und nicht pf32bit wie ich erhofft hatte), das bedeutet das das PixelFormat vom jeweiligen anzeigendem Device abhängig ist. Leider sind ALLE Farbbitmaps von Icons, egal ob XP, 24bit oder 256 bzw. 16 Farben, beim PixelFormat vom Typ pfDevice. Sprich ich kann nicht unterscheiden ob ich nen XP Icon habe oder nicht, folglich kann ich nicht entscheiden ob ich die Bitmap mit den Farbinformationen noch bearbeiten muss oder nicht und wenn ich das Ding bearbeite obwohl ichs nicht soll, dann sehen XP Icons ziemlich dämlich aus. erster Lösungversuch: Über den PixelFormatDescriptor rauskriegen von welchem Typ das Bitmap ist. Folgender Code:
Delphi-Quellcode:
Wie schon im Code am Kommentar ersichtlich, ist die Funktion DescribePixelFormat saulahm, sprich für ca. 6 Bitmaps braucht mein Rechner 2-3 Sekunden, da das Ganze eigntlich eher so ca. 20 Bitmaps aufeinma abchecken muss, kann das nicht einfach mal 7-10 Sekunden dauern.
function IconToBitmap(const IconHandle: HIcon):TBitmap;
var IcoInfo: TIconInfo; mask: TBitmap; x, y: word; ColorSL, MaskSL: pRGBALine; pfd: PixelFormatDescriptor; begin result := nil; if NOT GetIconInfo(IconHandle, IcoInfo) then exit; try try result := TBitmap.Create; result.Handle := IcoInfo.hbmColor; mask := TBitmap.Create; mask.Handle := IcoInfo.hbmMask; mask.PixelFormat := pf32bit; DescribePixelFormat(result.Canvas.Handle, 1, sizeof(PixelFormatDescriptor), pfd); // Tiiiiiiiiiiierisch laaaaaaaaaaaaaaahm if pfd.iPixelType <> PFD_TYPE_RGBA then begin result.PixelFormat := pf32bit; for y := 0 to result.Height-1 do begin ColorSL := result.Scanline[y]; MaskSL := mask.ScanLine[y]; for x := 0 to result.Width-1 do ColorSL^[x].rgbReserved := NOT MaskSL^[x].rgbRed; end; end; except FreeAndNil(result); end; finally if Assigned(mask) then mask.Free; end; end; Habt ihr noch ne Ahnung was man da machen könnte, was auch einigermaßen schnell ist ? Danke schon mal im Vorraus - Thebe |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Bisr du sicher, dass es nicht eher an deiner Schleife liegt:
Delphi-Quellcode:
Was ist das eigentlich für eine kranke Einrückung mit Tabulatoren?
for y := 0 to result.Height-1 do
begin ColorSL := result.Scanline[y]; MaskSL := mask.ScanLine[y]; for x := 0 to result.Width-1 do ColorSL^[x].rgbReserved := NOT MaskSL^[x].rgbRed; end; |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Ich kann Dir definitiv versichern, das es nicht an dem rüberkopieren des Alphakanals liegt. Die Frage hat sich mir nämlich beim PixelFormatDescriptor auch gestellt und ich habe die komplette Bedingung (in der herumkopiert wird) auskommentiert und das Zeug war immernoch so saumäßig lahm.
Kommentiere ich hingegen DescribePixelFormat aus und ersetze die Bedingung durch eine wie "if true = true then ..." geht es ziemlich schnell und das obwohl der AlphaKanal immer rüberkopiert wird. |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Zitat:
![]() ![]() |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Wunderbare Idee, daran hab ich gar nicht gedacht die DeviceCaps vom Bild abzufragen, nur leider hab ich das Problem das eben jene Bilder die ich per GetIconInfo() erhalte, so ziemlich gleiche Werte liefern.
Ich hab 5 Icons abgefragt, 3 sind 32bit Icons, 2 sind 24bit Icons. GetDeviceCaps(Handle, BITSPIXEL) liefert jedesmal 32 (auch bei den 24bit Icons). GetDeviceCaps(Handle, COLORRES) liefert jedesmal 24. (Kann ich leider auch nit zur Unterscheidung nutzen) Sprich, zurück ans Zeichenbrett *gnarf* Aber war schonma ne gute Idee, Danke Dir! :) |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Hm, Schnellschuss :):
Es gibt: a) Bitmap 24Bit mit 1Bit Maske b) Bitmap 32Bit mit 1Bit Maske, aber auch mit Alpha im höchsten Byte der Farbwerte Nun wäre interessant ob die 24-Bitter wegen des Alignments nicht auch mit 32Bit pro Pixel gespeichert werden. Wäre dem nicht so, wärst du mit einem Vergleich "Bildgröße:Dateigröße" dabei -> der 24-Bitter wäre in Bytes ausgedrückt kleiner. Sollte es aber doch so sein dass die 24er 32bpp belegen, so wäre interessant was dort im höchsten Byte steht. Mal angenommen wir haben Glück und sie sind immer $00: Dann kannst du zunächst mal alle als 32er ansehen. Wenn sich auch nur eines dieser Bytes findet dass nicht 0 ist, wäre anzunehmen du hast ein echtes 32bpp Bitmap, und die 1Bit-Maske hat keine Bedeutung. Sind jedoch alle 0, wäre beides möglich, aber es macht keinen Unterschied mehr - du kannst die 1Bit-Maske blind anwenden. Damit wird ein 24er korrekt maskiert, und beim 32er ist die Maske eh komplett leer, so dass sie nichts am Bild ändert. (Das setzt jedoch voraus, dass die 1Bit-Makse bei den 32ern am Alpha-Byte orientiert ist, und nicht separat davon "schrott" enthalten kann. Das weiss ich nicht.) Ich hoffe dieser nächtliche Gedankenanflug ist nicht allzu abwegig :D Gruss, Fabian |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Liste der Anhänge anzeigen (Anzahl: 1)
1. Ansatz: benutze GetIconInfo - das liefert dir die beiden Bitmaps (Maske und Bild) als separate Bitmaps. Die sind (so meine ich) DIB-Sections, also geräteunabhängig. Wenn die Masken-Bitmap 0 ist (also leer), dann benutzt die Bild-Bitmap Alphablending (und sonst die Maske).
2. Ansatz: Wenn du die Icons als Dateien vorliegen hast, kannst du auch alle Informationen direkt daraus lesen. Ich habe mal zwei Units von mir angehängt mit denen das ansatzweise geht (unfertig, Work in Progress). Bitmaps extrahieren geht aber schon. |
Re: TBitmap.Pixelformat = pfDevice! Check auf 32Bit ?
Hihoooo
@Dizzy: Es ist anscheinend tatsächlich so, daß 24bit Bitmaps auch 32Bpp belegen. Der Alphakanal bei den 24bit Bitmaps ist natürlich leer, weil diese Informationen nicht abgespeichert werden im jeweiligen Icon. Ich bin gestern zur ca. der gleichen Zeit wie Du auf die Idee gekommen, den Alphakanal einfach auszulesen ob der ungleich 0 ist. Die Maske ist leider immer existend, die kann ich nicht auslesen um zu bestimmen was es fürn Icon ist. Schätze ma das sind auch wieder solche Kompatibilitätszwecke, weil nen Win98 Rechner mit den Icons ja auch was anfangen muss, würde da die Maske fehlen wärs ziemlich schlimm. @Flocke: Ich hab ja leider nur das Handle von den Icons und keine Datei, das is das Problem. Deswegen nutz ich schon Ansatz 1 mit GetIconInfo (s.o. im Code), nur leider sind die ja DeviceDependentBitmaps, sprich PixelFormat = pfDevice. Lösung 2: Auslesen des Alphakanals des ColorBitmaps. Ist nicht wirklich mein Favorit, da ich nicht weiß wie ne 1,4ghz Maschine damit klar kommt, aber bei mir funktioniert es in recht kurzer Zeit. Es schmeckt mir nur nicht wirklich, um rauszukriegen ob eine Bitmap 24 oder 32bittig ist, gleich die komplette Bitmap per Scanline analysieren zu müssen, man sollte meinen das wäre mit nem Performance-schonenderem "if 32bit then HauReinUndTuWas();" möglich. Hier erstma der Code bis dato
Delphi-Quellcode:
Das funkt soweit, nur finde ich schaut das eher aus als wenn ich mit Kannonen auf Spatzen schießen würde, statt adäquat der Situation entsprechend einen Wert auszulesen.
function IconToBitmap(const IconHandle: HIcon):TBitmap;
var IcoInfo: TIconInfo; // Icon Info mit beiden Bitmaps mask: TBitmap; // TBitmap für Maskierungsbitmap // result: TBitmap; // TBitmap für das Farbinformationsbitmap x, y: word; // Zählvariablen AnSL, AnSL2: pRGBALine; // Scanline Arrays für Color BMP und für Mask BMP xp: boolean; // Boolean Wert ob bei der Analysierung ein XP Icon entdeckt wurde begin // Aus dem Icon Handle die beiden Bitmaps - Color und Mask - rauskriegen. Wenn nicht, dann gleich Ende result := nil; if NOT GetIconInfo(IconHandle, IcoInfo) then exit; try try result := TBitmap.Create; result.Handle := IcoInfo.hbmColor; result.PixelFormat := pf32bit; mask := TBitmap.Create; mask.Handle := IcoInfo.hbmMask; mask.PixelFormat := pf32bit; // Color Bitmap analysieren, ob alle Alphawerte = 0 sind. Wenn ja, dann bleibt xp = false. Wenn nur ein Wert != 0 gefunden wurde, dann ist ein XP Icon gefunden worden und die Schleife bricht ab. xp := false; AnSL := result.ScanLine[result.Height-1]; x := 0; while ((x < (result.Height*result.Width)) and (xp = false)) do begin xp := xp or (AnSL^[x].rgbReserved <> 0); inc(x); end; // Wenn kein XP Icon gefunden wurde, dann die Maskierungsinformationen aus der Mask BMP in den Alphakanal des Color Bitmaps reinkopieren. Da die Maskierung entweder Weiß oder Schwarz ist (sprich alle RGB Werte gleich), wird stellvertretend für den Maskierungswert Rot genommen if not xp then begin for y := 0 to result.Height-1 do begin AnSL := result.Scanline[y]; AnSL2 := mask.ScanLine[y]; for x := 0 to result.Width-1 do AnSL^[x].rgbReserved := NOT AnSL2^[x].rgbRed; end; end // Eigener Hack: AlphaBlend() zeigt bei mir ein merkwürdiges Verhalten. Wenn von einem Pixel der Alpha Wert 0 ist und die Pixelfarbe in den helleren Bereich wie weiß, helles gelb etc. geht, dann wird trotz Alpha=0 das weiße Pixel bei AlphaBlend in ein anderes Bitmap kopiert. Als Fix dafür werden alle Pixel schwarz gemacht, die einen Alphawert von kleiner 100 haben, sprich eigentlich sowieso nur für den obligatorischen Schlagschatten zuständig sind und der immer schwarz ist. else begin for x := 0 to (result.Height*result.Width)-1 do if AnSL^[x].rgbReserved < 100 then begin AnSL^[x].rgbRed := 0; AnSL^[x].rgbGreen := 0; AnSL^[x].rgbBlue := 0; end; end; except FreeAndNil(result); end; finally if Assigned(mask) then mask.Free; end; end; Ich suche noch weiter nach Methoden dieses Analysieren zu umgehen, sowas muss ja nicht sein. Vielen Dank wieder mal für Eure Antworten! :thumb: - Thebe |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:59 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