Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Farbe wird verändert (https://www.delphipraxis.net/192643-farbe-wird-veraendert.html)

EWeiss 8. Mai 2017 07:09


Farbe wird verändert
 
Ich verwende diese Funktion um Bitmaps Transparent abzuspeichern.

Das Problem ist nur das diese anscheinend nicht korrekt arbeitet.
Was könnte da falsch sein. ?

oder aber ich initialisiere das TBitmap falsch.

zum vergleich "1" das dunkle ist von dieser Funktion das andere Original.
Delphi-Quellcode:
procedure TSkinEngine.SaveBitmapToFile(ImgFile: WideString; hbmp: HBITMAP);
var
  png: TPNGImage;
  ext : string;
  Bitmap: TBitmap;
begin
  ext := ExtractFileExt(ImgFile) ;
  if SameText(ext, '.png') then
  begin
    Bitmap := TBitmap.Create;
    Bitmap.Handle := hbmp;
    Bitmap.PixelFormat := pf32bit;
    Png := PNG4TransparentBitMap(Bitmap);
    try
      png.SaveToFile(ImgFile);
    finally
      png.Free;
      Bitmap.Free;
    end;
  end;
end;
Eine andere Fehlerquelle könnte auch diese sein.

Delphi-Quellcode:
procedure SetupAlphaChannel(DC: HDC);
var
  bm: BITMAP;
  P: integer;
  Alpha: Byte;
  pBits: PRGBQuad;
begin

  FillChar(bm, sizeof(bm), 0);

  GetObject(GetCurrentObject(DC, OBJ_BITMAP), sizeof(bm), @bm);
  pBits := bm.bmBits;
  for P := (bm.bmWidth * bm.bmHeight) downto 1 do
  begin
    Alpha := SKAERO_Rgb2Gray(RGB(pBits.rgbRed, pBits.rgbGreen, pBits.rgbBlue)) and $000000FF;
    if (Alpha = 0) and (pBits.rgbReserved = 0) then
      pBits.rgbReserved := 0
    else if (pBits.rgbReserved = 0) then
      pBits.rgbReserved := 255;

    inc(pBits);
  end;
end;
Delphi-Quellcode:
function TSkinEngine.Rgb2Gray(RGBValue: COLORREF): COLORREF;
asm
  XOR ESI, ESI
  XOR EDX, EDX
  MOV ECX, RGBValue

  // Red
  MOV EAX, 19595
  MOV DL, CL
  MUL EDX
  ADD ESI, EAX

  // Green
  MOV EAX, 38470
  SHR ECX, 8
  MOV DL, CL
  MUL EDX
  ADD ESI, EAX

  // Blue
  MOV EAX, 7471
  SHR ECX, 8
  MOV DL, CL
  MUL EDX
  ADD ESI, EAX

  SHR ESI, 16
  MOV EDX, ESI

  //' Put Gray Value to a DWORD (0GGG)
  XOR EAX, EAX
  OR AL, DL
  SHL EAX, 8
  OR AL, DL
  SHL EAX, 8
  OR AL, DL

  MOV RESULT, EAX
end;
sorry ASM ist ein rotes Tuch für mich.
Wenn ich jedoch SetupAlphaChannel deaktiviere habe ich das gleiche Resultat.
Entweder ist diese in Verbindung mit RGB2Gray fehlerhaft so das es keine rolle spielt ob ich diese deaktiviere
oder die obere(der Link) berechnet die Farben nicht korrekt.


gruss

Amateurprofi 8. Mai 2017 09:46

AW: Farbe wird verändert
 
Die Funktion Rgb2Gray macht im Prinzip folgendes
Gray:=Trunc(R*0.299 + G*0.587 + B*0.114)
Result:=Gray shl 16 or Gray shl 8 or Gray
Hierbei sind R,G,B die im RgbValue enthaltenen Farbanteile

Bedenklich erscheint mir, dass das Register ESI verändert wird was zu unvorhersehbaren Problemen führen kann.
Vermutlich ist das aber nicht die Ursache für dein Problem, denn die Abweichung tritt ja auch dann auf wenn die Funktion Rgb2Gray nicht eingesetzt wird.

Unabhängig hiervon würde ich abraten, die Funktion Rgb2Gray zu benutzen oder am Anfang ein Push ESI und am Ende ein Pop ESI einzufügen.

Alternativ kannst du die nachstehende Funktion RgbToGray verwenden, die deutlich kompakter ist, identische Resultate liefert und zusätzlich zu eax,edx,ecx keine weiteren Register braucht.

Code:
FUNCTION RGBtoGray(Value:ColorRef):ColorRef;
asm
      movzx   edx,al
      imul    edx,19595  // Red
      movzx   ecx,ah
      imul    ecx,38470  // Greean
      shr     eax,16
      imul    eax,7471   // Blue
      add     eax,ecx
      add     eax,edx
      shr     eax,16
      mov     ah,al
      shl     eax,8
      mov     al,ah
end;

EWeiss 8. Mai 2017 16:30

AW: Farbe wird verändert
 
Zitat:

Alternativ kannst du die nachstehende Funktion RgbToGray verwenden
.
Danke ich werde sie mal testen und kann dabei nur auf dein wissen bezgl. ASM vertrauen.

Wo wird denn die Farbe zurück gegeben?
Bei (meiner) Funktion mit RESULT.

Wie gesagt ist ein rotes Tuch für mich.
Danke.

gruss

EWeiss 8. Mai 2017 17:16

AW: Farbe wird verändert
 
Es ist ein alt bekanntes Problem das beim laden von Transparenten PNG's die Transparenz verändert werden kann.
Deshalb habe ich ja diese Funktion um das zu verhindern.


Definition
Delphi-Quellcode:
  pBits: PRGBQuad;
Delphi-Quellcode:
AlphaCoef: Single;
Delphi-Quellcode:
        for y := 0 to (h - 1) do
        begin
          for x := 0 to (w - 1) do
          begin
            if pBits.rgbReserved > 0 then
            begin
              AlphaCoef := (pBits.rgbReserved / 255);
              pBits.rgbBlue := round(pBits.rgbBlue / AlphaCoef);
              pBits.rgbGreen := round(pBits.rgbGreen / AlphaCoef);
              pBits.rgbRed := round(pBits.rgbRed / AlphaCoef);
            end;
            inc(pBits);
          end;
        end;
definition
AlphaCoef: Byte;
Delphi-Quellcode:
        for y := 0 to (h - 1) do
        begin
          for x := 0 to (w - 1) do
          begin
            if pBits.rgbReserved > 0 then
            begin
              AlphaCoef := pBits.rgbReserved div 255;
              if AlphaCoef > 0 then
              begin
                pBits.rgbBlue := pBits.rgbBlue div AlphaCoef;
                pBits.rgbGreen := pBits.rgbGreen div AlphaCoef;
                pBits.rgbRed := pBits.rgbRed div AlphaCoef;
              end if
            end;
            inc(pBits);
          end;
        end;
Aber beide bringen nicht den gewünschten Effekt.
Die Transparente Farbe verändert sich.

siehe Shot.

gruss

Amateurprofi 8. Mai 2017 20:04

AW: Farbe wird verändert
 
[QUOTE=EWeiss;1370598]
Zitat:

Wo wird denn die Farbe zurück gegeben?
Bei (meiner) Funktion mit RESULT.
Bei meiner im Prinzip auch.
Assemblerfunktionen geben ordinale 32Bit-Werte in EAX zurück, 16Bit-Werte in AX und 8Bit-Werte in AL.
Das MOV Result,EAX in deiner Version ist also nicht erforderlich, denn das Ergebnis steht ja schon in EAX.
Tatsächlich ist solch eine Konstruktion eher schädlich denn sie wird in etwa so umgesetzt:
MOV [EBP-4], EAX
MOV EAX, [EBP-4]
also Speichern von EAX ins RAM, dann Lesen des soeben gespeicherten Wertes aus dem RAM in EAX.

Du kannst die korrekte Funktion ja prüfen, indem du für alle möglichen Colorref werte prüfst, ob meine Funktion die gleichen Ergebnisse bringt wie deine.

EWeiss 8. Mai 2017 20:22

AW: Farbe wird verändert
 
Danke für die Info. ;)

Habe sie mal eingebaut das Resultat sehe ich spätestens dann wenn meine Farbe funktioniert ;)

gruss

EWeiss 10. Mai 2017 06:04

AW: Farbe wird verändert
 
Mein Icon hat jetzt die richtige Farbe von daher ist das Thema erst mal erledigt.
Es lag aber nicht an der Funktion RGB2GRAY.

Ich musste dazu extra noch die Alpha Werte neu zuordnen.

gruss

Blup 10. Mai 2017 09:22

AW: Farbe wird verändert
 
Ich habe mich mal an der Funktion "PNG4TransparentBitMap" versucht, eigentlich sollte nur für das AlphaFormat "afPremultiplied" einer Sonderbehandlung notwendig sein.
Delphi-Quellcode:
function PNG4TransparentBitMap(bmp: TBitmap): TPNGImage;
var
  x, y: Integer;
  vBmpRGBA: ^TRGBAArray;
  vPngRGB: ^TRGB;
  vAlpha: Single;
begin
  Result := TPNGImage.CreateBlank(COLOR_RGBALPHA, 8, bmp.Width , bmp.Height);
  Result.CreateAlpha;

//  {Wenn diese Alphaformate nicht gesondert behandelt werden müssen:}
//  if bmp.AlphaFormat in [afIgnored, afDefined] then
//  begin
//    Result.Canvas.CopyMode:= cmSrcCopy;
//    Result.Canvas.Draw(0,0,bmp);
//  end
//  else

  for y := 0 to pred(bmp.Height) do
  begin
    vBmpRGBA := bmp.ScanLine[y];
    vPngRGB := Result.Scanline[y];

    for x := 0 to pred(bmp.width) do
    begin
      Result.AlphaScanline[y][x] := vBmpRGBA[x].A;
      vPngRGB^.b := vBmpRGBA[x].b;
      vPngRGB^.r := vBmpRGBA[x].r;
      vPngRGB^.g := vBmpRGBA[x].g;

      case bmp.AlphaFormat of
        afIgnored:
          Result.AlphaScanline[y][x] := 255;
        afPremultiplied:
          begin
            if vBmpRGBA[x].A <> 0 then
            begin
              vAlpha := 255 / vBmpRGBA[x].A;
              vPngRGB^.b := round(vPngRGB^.b * vAlpha);
              vPngRGB^.r := round(vPngRGB^.r * vAlpha);
              vPngRGB^.g := round(vPngRGB^.g * vAlpha);
            end
            else
            begin
              {voll transparente Bereiche weiß}
              vPngRGB^.b := 255;
              vPngRGB^.r := 255;
              vPngRGB^.g := 255;
            end
          end;
        afDefined:
          ;
      end;

      inc(vPngRGB);
    end;
  end;
end;

EWeiss 10. Mai 2017 15:43

AW: Farbe wird verändert
 
Hmm.. also ich muss das teil nochmal extra durch diese Funktion jagen damit mein Image die Transparente Farbe behält.
Lasse ich sie weg ist das Image Grau.
Delphi-Quellcode:
         if GetObject(hbmReturn, sizeof(bm), @bm) <> 0 then
         begin
           pBits := bm.bmBits;

           for a := 0 to (Height - 1) do
           begin
             for b := 0 to (Width - 1) do
             begin
               if pBits.rgbReserved > 0 then
               begin
                 AlphaCoef := (pBits.rgbReserved / 255);
                 pBits.rgbBlue := round(pBits.rgbBlue / AlphaCoef);
                 pBits.rgbGreen := round(pBits.rgbGreen / AlphaCoef);
                 pBits.rgbRed := round(pBits.rgbRed / AlphaCoef);
               end;
               inc(pBits);
             end;
           end;
         end;
Also deine geänderte Version zerschießt die ganze Transparenz.
Habe es extra mal getestet.

gruss

EWeiss 11. Mai 2017 07:41

AW: Farbe wird verändert
 
So hab wieder die ganze Nacht rumgemacht jetzt funktionieren die Farben wie sie sollen.

Zum vergleich.. das Bild in diesen Beitrag und das hier.
Damit ist das erst mal erledigt.

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:40 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz