프로그래밍/델파이

비트맵 이미지를 회전하는 메소드

채윤아빠 2007. 12. 22. 00:12
728x90
반응형

비트맵 이미지를 회전하는 메소드 입니다.


{** 이미지를 회전시킨다.
  @param  SourceBitmap 원본 비트맵
  @param  DestBitmap 회전된 이미지 비트맵
  @param  dAngle 회전 방향은 반시계 방향. 0~360 사이의 각도
  @param  clBackground 배경색
  *}
procedure RotateBitmap(SourceBitmap, DestBitmap: TBitmap; dAngle: Double; clBackground: TColor);
const
  MaxPixelCount = 32768;
type
  PRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = array[0..MaxPixelCount] of TRGBTriple;
var
  A: Extended;
  CosTheta: Extended;
  SinTheta: Extended;
  xSrc, ySrc: Integer;
  xDst, yDst: Integer;
  xODst, yODst: Integer;
  xOSrc, yOSrc: Integer;
  xPrime, yPrime: Integer;
  srcRow, dstRow: PRGBTripleArray;
begin
  // Workaround SinCos bug
  while A >= 360 do A := A - 360;
  while A < 0 do A := A + 360;
  // end of workaround SinCos bug
  SinCos(A * Pi / 180, SinTheta, CosTheta);
  if (SinTheta * CosTheta) < 0 then
  begin
    DestBitmap.Width := Round(Abs(SourceBitmap.Width * CosTheta - SourceBitmap.Height * SinTheta));
    DestBitmap.Height := Round(Abs(SourceBitmap.Width * SinTheta - SourceBitmap.Height * CosTheta));
  end
  else
  begin
    DestBitmap.Width := Round(Abs(SourceBitmap.Width * CosTheta + SourceBitmap.Height * SinTheta));
    DestBitmap.Height := Round(Abs(SourceBitmap.Width * SinTheta + SourceBitmap.Height * CosTheta));
  end;
  with DestBitmap.Canvas do
  begin
    Brush.Color := clBackground;
    Brush.Style := bsSolid;
    FillRect(ClipRect);
  end;
  DestBitmap.PixelFormat := pf24bit;
  SourceBitmap.PixelFormat := pf24bit;
  xODst := DestBitmap.Width div 2;
  yODst := DestBitmap.Height div 2;
  xOSrc := SourceBitmap.Width div 2;
  yOSrc := SourceBitmap.Height div 2;
  if CosTheta < 0 then Dec(xOSrc);
  if SinTheta < 0 then Dec(yOSrc);
  for ySrc := Max(SourceBitmap.Height, DestBitmap.Height)-1 downto 0 do
  begin
    yPrime := ySrc - yODst;
    for xSrc := Max(SourceBitmap.Width, DestBitmap.Width)-1 downto 0 do
    begin
      xPrime := xSrc - xODst;
      xDst := Round(xPrime * CosTheta - yPrime * SinTheta) + xOSrc;
      yDst := Round(xPrime * SinTheta + yPrime * CosTheta) + yOSrc;
      if (yDst >= 0) and (yDst < SourceBitmap.Height) and
         (xDst >= 0) and (xDst < SourceBitmap.Width) and
         (ySrc >= 0) and (ySrc < DestBitmap.Height) and
         (xSrc >= 0) and (xSrc < DestBitmap.Width) then
      begin
        srcRow := SourceBitmap.ScanLine[yDst];
        dstRow := DestBitmap.Scanline[ySrc];
        dstRow[xSrc] := srcRow[xDst];
      end;
    end;
  end;
end;