Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   [gelöst] TBitmap drehen (https://www.delphipraxis.net/182882-%5Bgeloest%5D-tbitmap-drehen.html)

Schwedenbitter 23. Nov 2014 23:09


[gelöst] TBitmap drehen
 
Dieses Thema gibt es schon des öfteren hier und auch entsprechende ("langsamere") Lösungen. Allerdings soll das ganze in einem zeitkritischen Prozess ablaufen, weshalb ich nach vielfachen Tests bei diesem Code gelandet bin, der für mich schnell genug ist.

Ich möchte das ganze zu einer Funktion zusammenfassen. Aber irgendwie stelle ich mich bei der 180°-Drehung zu blöd an. Ich erhalte bei der Ausführung immer nur Datenmüll. Ich probiere jetzt schon eine Ewigkeit rum und finde meinen Fehler nicht:
Delphi-Quellcode:
// Rotiert das angegebene Bitmap in 90°-Schritten ------------------------------
Type
   TRotateDir   = (rdLeft = 0, rdRight, rdUpturn);

Procedure RotateBitmap(Const Bitmap: TBitmap;
   Const RotateDir: TRotateDir = rdLeft);
Type
   TRGBArray      = Array [0..0] Of TRGBTriple;
   pRGBArray      = ^TRGBArray;
   THelpRGB         = Packed Record
                        rgb         : TRGBTriple;
                        alpha         : Byte;
                    End;
Var
   oldPF         : TPixelFormat;
   header      : TBitmapInfo;
   dc            : hDC;
   P            :^THelpRGB;
   H, W         : Integer;
   I, J         : Integer;
   RowOut      : pRGBArray;
Begin
   oldPF:=Bitmap.PixelFormat;
   With TMemoryStream.Create Do
   Try
      SetSize(Bitmap.Height * Bitmap.Width * 4);
      Bitmap.PixelFormat:=pf24bit;
      With header.bmiHeader Do
      Begin
         biSize:=        SizeOf(TBITMAPINFOHEADER);
         biWidth:=       Bitmap.Width;
         biHeight:=      Bitmap.Height;
         biPlanes:=      1;
         biBitCount:=    32;
         biCompression:= 0;
         biSizeimage:=   Size;
         biXPelsPerMeter:=1;
         biYPelsPerMeter:=1;
         biClrUsed:=     0;
         biClrImportant:= 0;
      End;
      dc:=GetDC(0);
      P:=Memory;
      GetDIBits(dc, Bitmap.Handle, 0, Bitmap.Height, P, header, dib_RGB_Colors);
      ReleaseDC(0, dc);

      H:=Bitmap.Height;   W:=Bitmap.Width;            // Werte merken
      If (RotateDir <> rdUpturn) Then               // Falls kein 180° gewünscht
      Begin
         Bitmap.Width:= H;   Bitmap.Height:=W;         // um 90° drehen
      End;
      Case RotateDir of
         rdLeft   :   For J:=0 To Pred(W) Do
                     Begin
                        rowOut:=Bitmap.ScanLine[Pred(W) - J];
                        P:=Memory;                  // reset pointer
                        Inc(P, J);
                        For I:=Pred(H) Downto 0 Do
                        Begin
                           rowout[I]:=p^.rgb;
                           Inc(P, W);
                        End;
                     End;
         rdRight   :   For J:=0 To Pred(W) Do
                     Begin
                        rowOut:=Bitmap.ScanLine[J];
                        P:=Memory;                  // reset pointer
                        Inc(P, J);
                        For I:=0 To Pred(H) Do
                        Begin
                           rowout[I]:=p^.rgb;
                           Inc(P, W);
                        End;
                     End;
         rdUpturn   :   For J:=0 To Pred(H) Do   // <- funktioniert leider nicht :-(
                     Begin
                        rowOut:=Bitmap.ScanLine[Pred(H) - J];
                        P:=Memory;                  // reset pointer
                        Inc(P, J);
                        For I:=Pred(W) Downto 0 Do
                        Begin
                           rowOut[I]:=p^.rgb;
                           Inc(P, H);
                        End;
                     End;
      End;
   Finally
      Free;
   End;
   Bitmap.PixelFormat:=oldPF;
End;
Ich bin mir (fast) sicher, dass es nur eine Kleinigkeit ist. Nachdem ich aber jetzt schon 3h an der Sache tüfftle, sehe ich so langsam den Wald vor lauter Bäumen nicht mehr.

Wo liegt mein Fehler?

Dejan Vu 24. Nov 2014 06:39

AW: TBitmap drehen
 
Vielleicht ist die Schleife einfach komplett falsch (P wird falsch gesetzt und falsch erhöht => Copy&Paste Fehler):
Delphi-Quellcode:
 P := Memory;
 For J:=0 To Pred(H) Do  // <- funktioniert leider nicht :-(
 Begin
   rowOut:=Bitmap.ScanLine[Pred(H) - J];
   For I:=Pred(W) Downto 0 Do
   Begin
     rowOut[I]:=p^.rgb;
     Inc(P);
   End;
 End;
Das sollte imho funktionieren (ungestestet)

Schwedenbitter 24. Nov 2014 13:21

AW: TBitmap drehen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1280861)
Vielleicht ist die Schleife einfach komplett falsch (P wird falsch gesetzt und falsch erhöht => Copy&Paste Fehler)
...
Das sollte imho funktionieren (ungestestet)

Tausend Dank!
War also doch ein Denkfehler, weil P zeilenweise erhöht werden muss. Der (ungetestete) Code spiegelt das Ganze - sieht lustig aus und merke ich mir vor, falls ich es mal brauche! Aber wenn man dann noch den Zeilen-Zähler anpasst, passt es perfekt.
Delphi-Quellcode:
         rdUpturn   :   Begin
                        P:=Memory;                  // reset pointer
                        For J:=0 To Pred(H) Do
                        Begin
                           rowOut:=Bitmap.ScanLine[J];
                           For I:=Pred(W) Downto 0 Do
                           Begin
                              rowOut[I]:=p^.rgb;
                              Inc(P);
                           End;
                        End;
                     End;
:dp:

Dejan Vu 24. Nov 2014 13:25

AW: [gelöst] TBitmap drehen
 
He he: stimmt (mit dem Spiegeln)...


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:15 Uhr.

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