unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 =
class(TForm)
Button1: TButton;
image: TImage;
procedure Button1Click(Sender: TObject);
FUNCTION Rotate(
CONST BitmapOriginal: TBitmap;
CONST iRotationAxis, jRotationAxis: INTEGER;
CONST AngleOfRotation: DOUBLE
{radians} ): TBitmap;
private
{ Private declarations }
public
{ Public declarations }
end;
CONST
MaxPixelCount = 32768;
TYPE
TRGBTripleArray =
ARRAY[0..MaxPixelCount-1]
OF TRGBTriple;
pRGBTripleArray = ^TRGBTripleArray;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
rotate(image,12,34,56);
end;
// "Simple" approach. For pixel (i,j), use "reverse" rotation to find
// where the rotated pixel must have been before the rotation.
// Don't bother with center of pixel adjustment.
// Assumes input BitmapOriginal has PixelFormat = pf24bit.
FUNCTION Rotate(
CONST BitmapOriginal: TBitmap;
CONST iRotationAxis, jRotationAxis: INTEGER;
CONST AngleOfRotation: DOUBLE
{radians} ): TBitmap;
VAR
cosTheta : EXTENDED;
i : INTEGER;
iOriginal : INTEGER;
iPrime : INTEGER;
j : INTEGER;
jOriginal : INTEGER;
jPrime : INTEGER;
RowOriginal: pRGBTripleArray;
RowRotated : pRGBTRipleArray;
sinTheta : EXTENDED;
BEGIN
// The size of BitmapRotated is the same as BitmapOriginal. PixelFormat
// must also match since 24-bit GBR triplets are assumed in ScanLine.
RESULT := TBitmap.Create;
RESULT.Width := BitmapOriginal.Width;
RESULT.Height := BitmapOriginal.Height;
RESULT.PixelFormat := pf24bit;
// Force this
// Get SIN and COS in single call from math library
sinTheta := SIN(AngleOfRotation);
// If no math library, then use this:
// sinTheta := SIN(AngleOfRotation);
// cosTheta := COS(AngleOfRotation);
// Step through each row of rotated image.
FOR j := RESULT.Height-1
DOWNTO 0
DO
BEGIN
RowRotated := RESULT.Scanline[j];
jPrime := j - jRotationAxis;
FOR i := RESULT.Width-1
DOWNTO 0
DO
BEGIN
iPrime := i - iRotationAxis;
iOriginal := iRotationAxis + ROUND(iPrime * CosTheta - jPrime * sinTheta);
jOriginal := jRotationAxis + ROUND(iPrime * sinTheta + jPrime * cosTheta);
// Make sure (iOriginal, jOriginal) is in BitmapOriginal. If not,
// assign blue color to corner points.
IF (iOriginal >= 0)
AND (iOriginal <= BitmapOriginal.Width-1)
AND
(jOriginal >= 0)
AND (jOriginal <= BitmapOriginal.Height-1)
THEN BEGIN
// Assign pixel from rotated space to current pixel in BitmapRotated
RowOriginal := BitmapOriginal.Scanline[jOriginal];
RowRotated[i] := RowOriginal[iOriginal]
END
ELSE BEGIN
RowRotated[i].rgbtBlue := 255;
// assign "corner" color
RowRotated[i].rgbtGreen := 0;
RowRotated[i].rgbtRed := 0
END
END
END
END {RotateBitmapMethod1};
end.