2009. augusztus 27., csütörtök

How to rotate a TBitmap smoothly


Problem/Question/Abstract:

I would like to rotate a TBitmap using a smooth algorithm but without clipping the corner of the bitmap. The size of the rotated bitmap change according to the angle.

Answer:

cx, cy represent the center of rotation.

function IntToByte(i: integer): byte;
begin
  if (i > 255) then
    Result := 255
  else if (i < 0) then
    Result := 0
  else
    Result := i;
end;

function TrimInt(i, Min, Max: integer): integer;
begin
  if (i > Max) then
    Result := Max
  else if (i < Min) then
    Result := Min
  else
    Result := i;
end;

procedure SmoothRotate(Src, Dst: TBitmap; cx, cy: integer; Angle: Extended);

type
  TFColor = record
    b, g, r: Byte
  end;

var
  Top, Bottom, Left, Right, eww, nsw, fx, fy, wx, wy: Extended;
  cAngle, sAngle: Double;
  xDiff, yDiff, ifx, ify, px, py, ix, iy, x, y: Integer;
  nw, ne, sw, se: TFColor;
  P1, P2, P3: PByteArray;
begin
  Src.PixelFormat := pf24Bit;
  Dst.PixelFormat := pf24Bit;
  Angle := -Angle * Pi / 180;
  sAngle := Sin(Angle);
  cAngle := Cos(Angle);
  xDiff := (Dst.Width - Src.Width) div 2;
  yDiff := (Dst.Height - Src.Height) div 2;
  for y := 0 to Dst.Height - 1 do
  begin
    P3 := Dst.scanline[y];
    py := 2 * (y - cy) + 1;
    for x := 0 to Dst.Width - 1 do
    begin
      px := 2 * (x - cx) + 1;
      fx := (((px * cAngle - py * sAngle) - 1) / 2 + cx) - xDiff;
      fy := (((px * sAngle + py * cAngle) - 1) / 2 + cy) - yDiff;
      ifx := Round(fx);
      ify := Round(fy);
      if (ifx > -1) and (ifx < Src.Width) and (ify > -1) and (ify < Src.Height) then
      begin
        eww := fx - ifx;
        nsw := fy - ify;
        iy := TrimInt(ify + 1, 0, Src.Height - 1);
        ix := TrimInt(ifx + 1, 0, Src.Width - 1);
        P1 := Src.scanline[ify];
        P2 := Src.scanline[iy];
        nw.r := P1[ifx * 3];
        nw.g := P1[ifx * 3 + 1];
        nw.b := P1[ifx * 3 + 2];
        ne.r := P1[ix * 3];
        ne.g := P1[ix * 3 + 1];
        ne.b := P1[ix * 3 + 2];
        sw.r := P2[ifx * 3];
        sw.g := P2[ifx * 3 + 1];
        sw.b := P2[ifx * 3 + 2];
        se.r := P2[ix * 3];
        se.g := P2[ix * 3 + 1];
        se.b := P2[ix * 3 + 2];
        Top := nw.b + eww * (ne.b - nw.b);
        Bottom := sw.b + eww * (se.b - sw.b);
        P3[x * 3 + 2] := IntToByte(Round(Top + nsw * (Bottom - Top)));
        Top := nw.g + eww * (ne.g - nw.g);
        Bottom := sw.g + eww * (se.g - sw.g);
        P3[x * 3 + 1] := IntToByte(Round(Top + nsw * (Bottom - Top)));
        Top := nw.r + eww * (ne.r - nw.r);
        Bottom := sw.r + eww * (se.r - sw.r);
        P3[x * 3] := IntToByte(Round(Top + nsw * (Bottom - Top)));
      end;
    end;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése