Delphi VCL: Obrót TImage – Inc(Dir,10), GDI+, Graphics32, Skia4Delphi, animacja bitmapy

Pytanie

Inc(Dir,10); jak obrócić timage

Odpowiedź Sztucznej Inteligencji


Bezpośrednia odpowiedź na pytanie

  • Komponent TImage w VCL nie ma własnej właściwości Angle – aby go obracać, trzeba obracać bitmapę znajdującą się w Image.Picture.Bitmap.
  • Najprostsze rozwiązania:
    • Obrót o wielokrotność 90 ° – własna, szybka procedura piksel-po-pikselu.
    • Obrót o dowolny kąt – GDI+ lub biblioteka Graphics32 (TAffineTransformation).
  • Fragment Inc(Dir, 10); można wykorzystać w zdarzeniu timera, a przy każdej zmianie kąta wywoływać procedurę rotacji.

Szczegółowa analiza problemu

1. Ogólna koncepcja

  1. Zapamiętaj oryginalną bitmapę (nie obracaj „wyniku rotacji”).
  2. Przy każdej zmianie kąta (Dir) wygeneruj nową bitmapę i przypisz ją do TImage.
  3. Dla płynnej animacji (timer 30–60 Hz) stosuj buforowanie lub akcelerowaną bibliotekę (Graphics32).

2. Procedury obrotu

2.1. Obrót o ±90 °, 180 °, 270 ° (bardzo szybki)
procedure Rotate90(const Src, Dst: TBitmap; CW: Boolean = True);
var x, y: Integer;
begin
  Dst.PixelFormat := pf24bit;
  Dst.SetSize(Src.Height, Src.Width);
  for y := 0 to Src.Height-1 do
    for x := 0 to Src.Width-1 do
      if CW then
        Dst.Canvas.Pixels[Src.Height-1-y, x] := Src.Canvas.Pixels[x, y]
      else
        Dst.Canvas.Pixels[y, Src.Width-1-x] := Src.Canvas.Pixels[x, y];
end;
2.2. Obrót o dowolny kąt – GDI+
uses Winapi.GDIPOBJ, Vcl.Imaging.GDIPlus, System.Math;
procedure RotateGDIPlus(const Src: TBitmap; Dst: TBitmap; Angle: Single);
var G: TGPGraphics; Img: TGPImage; CX, CY: Single;
begin
  Dst.SetSize(Src.Width, Src.Height);              // lub większy bufor
  Dst.PixelFormat := pf32bit;
  G   := TGPGraphics.Create(Dst.Canvas.Handle);
  Img := TGPImage.Create(Src);
  G.SetSmoothingMode(SmoothingModeAntiAlias);
  G.SetInterpolationMode(InterpolationModeHighQualityBicubic);
  CX := Src.Width / 2; CY := Src.Height / 2;
  G.TranslateTransform(CX, CY);
  G.RotateTransform(Angle);
  G.TranslateTransform(-CX, -CY);
  G.DrawImage(Img, 0, 0, Src.Width, Src.Height);
  Img.Free; G.Free;
end;
2.3. Obrót o dowolny kąt – Graphics32 (najwydajniejsze)
uses GR32, GR32_Transforms;
procedure RotateGR32(SrcBmp: TBitmap; DstBmp: TBitmap; Angle: Single);
var Src32, Dst32: TBitmap32; Tr: TAffineTransformation;
begin
  Src32 := TBitmap32.Create;  Dst32 := TBitmap32.Create;  Tr := TAffineTransformation.Create;
  try
    Src32.Assign(SrcBmp);
    Tr.SrcRect := FloatRect(0, 0, Src32.Width, Src32.Height);
    Tr.Rotate(0, 0, Angle * PI / 180);               // Graphics32 – radiany
    Dst32.SetSize(Round(Src32.Width*1.5), Round(Src32.Height*1.5));
    Tr.Transform(Dst32, Src32);
    DstBmp.Assign(Dst32);
  finally
    Src32.Free; Dst32.Free; Tr.Free;
  end;
end;

3. Sterowanie kątem (Timer + Inc)

var
  SrcBmp: TBitmap;     // oryginał
  Dir   : Integer = 0; // kąt w stopniach
procedure TForm1.FormCreate(Sender: TObject);
begin
  SrcBmp := TBitmap.Create;
  SrcBmp.LoadFromFile('obraz.png');
  Image1.Picture.Bitmap.Assign(SrcBmp);
  Timer1.Interval := 40;   // ≈25 FPS
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var Dst: TBitmap;
begin
  Inc(Dir, 10);          // <-- fragment z pytania
  if Dir >= 360 then Dir := Dir - 360;
  Dst := TBitmap.Create;
  try
    RotateGDIPlus(SrcBmp, Dst, Dir);
    Image1.Picture.Bitmap.Assign(Dst);
  finally
    Dst.Free;
  end;
end;

Aktualne informacje i trendy

  • Graphics32 1.9x pozostaje najpopularniejszą darmową biblioteką do szybkich transformacji 2-D w VCL; od 2023 r. rozwój przeniósł repozytorium na GitHub.
  • W FMX (FireMonkey) problem znika – TImage.RotationAngle i akceleracja GPU.
  • Coraz częściej wykorzystuje się SVG albo Skia4Delphi – biblioteka oparta na Google Skia, umożliwia ultraszybką, sprzętową rotację we wszystkich frameworkach.

Wspierające wyjaśnienia i detale

  • Anti-aliasing w GDI+ podwyższa jakość kosztem CPU; w rotacji animowanej można przełączyć na InterpolationModeLowQuality dla płynności.
  • Dla bitmap z kanałem alfa używaj pf32bit, aby zachować przezroczystość.
  • Zapobiegaj powiększeniu bufora w nieskończoność – po obrocie 45 ° obraz „wystaje”; możesz przyciąć lub zwiększyć rozmiar tła.

Aspekty etyczne i prawne

  • Graphics32 i Skia4Delphi rozpowszechniane są na licencji MPL / Apache 2.0 – można używać w oprogramowaniu komercyjnym, należy jednak dołączyć licencję w dokumentacji.
  • GDI+ jest częścią Windows ≥ XP, brak dodatkowych wymagań licencyjnych.

Praktyczne wskazówki

  • Buforuj bitmapy pośrednie: przy stałym rozmiarze można tworzyć jeden DstBitmap i tylko go nadpisywać.
  • Przy bardzo dużych obrazach zastosuj ograniczenie FPS lub zmniejsz obraz (mipmap).
  • W testach porównawczych (2024) Graphics32 obraca obraz FullHD ~5× szybciej od czystego GDI+.

Ewentualne zastrzeżenia lub uwagi dodatkowe

  • Rotacja „piksel-po-pikselu” bez interpolacji daje postrzępione krawędzie.
  • W GDI+ przy wielu cyklicznych obrotach może wystąpić smużenie kolorów – zawsze obracaj kopię Oryginału.
  • W Windows z włączonym skalowaniem DPI wartości współrzędnych trzeba przeliczać na urządzenie (Device-Independent Pixels).

Sugestie dalszych badań

  • Skia4Delphi (https://github.com/skia4delphi/skia4delphi) – pełny dostęp do GPU-accelerated Canvas.
  • Efekty pixel shader (FMX, D2D) – rotacja i jednoczesne cieniowanie lub przezroczystość.
  • Techniki multi-threading (TTask) do pre-rotacji klatek animacji.

Krótkie podsumowanie

Obrót TImage w klasycznym VCL wymaga obrotu bitmapy, nie samego komponentu.
Dla kątów 90/180/270 ° – wystarczy szybka zamiana współrzędnych pikseli.
Dla dowolnych kątów:
• GDI+ – łatwość implementacji, dobra jakość, średnia wydajność.
• Graphics32/Skia – najlepsza wydajność, antyaliasing i akceleracja sprzętowa.
Kod timera z Inc(Dir, 10); cyklicznie zwiększa kąt i wywołuje procedurę rotacji, dając płynną animację.

Oceń odpowiedź:

Zadaj dodatkowe pytanie Sztucznej Inteligencji

Czekaj (1min)...
Zastrzeżenie: Odpowiedzi udzielone przez sztuczną inteligencję (model językowy) mogą być niedokładne i wprowadzające w błąd. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi powinny być zweryfikowane przez użytkownika.