출처 : '채윤이네 집'님 블로그 ( https://hbesthee.tistory.com/87 )
{** 이미지를 회전시킨다.
@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 dAngle >= 360 do dAngle := dAngle - 360; // 원본에선 A로 해둬서 무한 루프에 빠짐.
while dAngle < 0 do dAngle := dAngle + 360;
// end of workaround SinCos bug
SinCos(dAngle * 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;