Recent Posts

Selamat datang di Coding Delphi Land Weblog kumpulan source code pemogram delphi

(Bukan maksud untuk menggurui tetapi marilah kita berbagi ilmu tuk perkembangan kemajuan teknologi kita

Sabtu, 14 November 2009

Rotate Image Scanline

unit ScreenRotateScanLine;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtDlgs, StdCtrls, ExtCtrls, Spin;

type
TFormRotateScanLine = class(TForm)
ImageOriginal: TImage;
ButtonLoad: TButton;
LabelImageInfo: TLabel;
ImageRotated: TImage;
LabelRotateTime: TLabel;
SpinEditThetaDegrees: TSpinEdit;
LabelDegreesClockwise: TLabel;
LabelRotationAngle: TLabel;
LabelCenter: TLabel;
SpinEditI: TSpinEdit;
SpinEditJ: TSpinEdit;
LabelI: TLabel;
LabelJ: TLabel;
CheckBoxStretch: TCheckBox;
SpinEditThetaDegreesHundredths: TSpinEdit;
Label1: TLabel;
OpenPictureDialog: TOpenPictureDialog;
ButtonSaveRotated: TButton;
SavePictureDialog: TSavePictureDialog;
procedure ButtonLoadClick(Sender: TObject);
procedure SpinEditRotate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure CheckBoxStretchClick(Sender: TObject);
procedure ButtonSaveRotatedClick(Sender: TObject);

private
{ Private declarations }
BitmapOriginal: TBitmap;
BitmapRotated : TBitmap;
public
PROCEDURE RotateBitmap;
end;

var
FormRotateScanLine: TFormRotateScanLine;

implementation
{$R *.DFM}

USES
{$IFDEF GIF}
GIFImage, // TGIFImage
{$ENDIF}
GraphicsConversionsLibrary, // LoadGraphicsFile
IniFiles, // TIniFile
ImageLib;

CONST
KeywordSetup = 'Setup';
KeywordDirectory = 'Directory';


// Load 24-bit color image from disk
procedure TFormRotateScanLine.ButtonLoadClick(Sender: TObject);
VAR
Filename: STRING;
NewPath : STRING;
IniFile : TIniFile;
begin
IF OpenPictureDialog.Execute
THEN BEGIN
BitmapOriginal.Free;
BitmapOriginal := LoadGraphicsFile(OpenPictureDialog.Filename);

IF BitmapOriginal.PixelFormat <> pf24bit
THEN BitmapOriginal.PixelFormat := pf24bit; // force to 24 bits

// Update INI file for next time
Filename := ChangeFileExt(ParamStr(0), '.INI');
NewPath := ExtractFilePath(OpenPictureDialog.Filename);
OpenPictureDialog.InitialDir := NewPath;
IniFile := TIniFile.Create(Filename);
TRY
Inifile.WriteString(KeywordSetup, KeywordDirectory, NewPath)
FINALLY
IniFile.Free
END;

// Flush INI cache
WritePrivateProfileString(NIL, NIL, NIL, pChar(Filename));


ImageOriginal.Picture.Graphic := BitmapOriginal;
LabelImageInfo.Caption := IntToStr(BitmapOriginal.Width) + ' by ' +
IntToStr(BitmapOriginal.Height) + ' pixels: ' +
OpenPictureDialog.Filename;

SpinEditI.Value := BitmapOriginal.Width DIV 2;
SpinEditJ.Value := BitmapOriginal.Height DIV 2;

// Rotate and display the image
RotateBitmap
END
end;


// Rotate image by angle[degrees] specified in spinbox
procedure TFormRotateScanLine.SpinEditRotate(Sender: TObject);
begin
RotateBitmap
end;


procedure TFormRotateScanLine.FormCreate(Sender: TObject);
VAR
IniFile : TIniFile;
begin
{$IFDEF GIF}
OpenPictureDialog.Filter := OpenPictureDialog.Filter +
'|GIFs|*.GIF';
{$ENDIF}

IniFile := TIniFile.Create(ChangeFileExt(ParamStr(0), '.INI'));
TRY
OpenPictureDialog.InitialDir := Inifile.ReadString(KeywordSetup,
KeywordDirectory,
ExtractFilePath(ParamStr(0)))
FINALLY
IniFile.Free
END;

BitmapOriginal := TBitmap.Create;
BitmapRotated := TBitmap.Create;
end;


procedure TFormRotateScanLine.FormDestroy(Sender: TObject);
begin
BitmapOriginal.Free;
BitmapRotated.Free
end;


PROCEDURE TFormRotateScanLine.RotateBitmap;
VAR
cosTheta : DOUBLE;
Delta : DWORD; // D3/D4 compatibility
i : INTEGER;
iRotationAxis : INTEGER;
iOriginal : INTEGER;
iPrime : INTEGER;
iPrimeRotated : INTEGER;
j : INTEGER;
jRotationAxis : INTEGER;
jOriginal : INTEGER;
jPrime : INTEGER;
jPrimeRotated : INTEGER;
RowOriginal : pRGBArray;
RowRotated : pRGBArray;
sinTheta : DOUBLE;
StartTime : DWORD;
Theta : DOUBLE; // radians
begin
// The size of BitmapRotated is the same as BitmapOriginal. PixelFormat
// must also match since 24-bit GBR triplets are assumed in ScanLine.
BitmapRotated.Width := BitmapOriginal.Width;
BitmapRotated.Height := BitmapOriginal.Height;
BitmapRotated.PixelFormat := pf24bit;

// "Start" the clock
StartTime := GetTickCount;

// Axis of rotation is normally center of image
TRY
iRotationAxis := SpinEditI.Value
EXCEPT
iRotationAxis := 0
END;

TRY
jRotationAxis := SpinEditJ.Value
EXCEPT
jRotationAxis := 0
END;

// Convert degrees to radians. Use minus sign to force clockwise rotation.
Theta := -(SpinEditThetaDegrees.Value +
SpinEditThetaDegreesHundredths.Value/100) *
PI / 180;
sinTheta := SIN(Theta);
cosTheta := COS(Theta);

// Step through each row of rotated image.
FOR j := BitmapRotated.Height-1 DOWNTO 0 DO
BEGIN
RowRotated := BitmapRotated.Scanline[j];

// Assume the bitmap has an even number of pixels in both dimensions and
// the axis of rotation is to be the exact middle of the image -- so this
// axis of rotation is not at the middle of any pixel.

// The transformation (i,j) to (iPrime, jPrime) puts the center of each
// pixel at odd-numbered coordinates. The left and right sides of each
// pixel (as well as the top and bottom) then have even-numbered coordinates.

// The point (iRotationAxis, jRotationAxis) identifies the axis of rotation.

// For a 640 x 480 pixel image, the center point is (320, 240). Pixels
// numbered (index i) 0..319 are left of this point along the "X" axis and
// pixels numbered 320..639 are right of this point. Likewise, vertically
// pixels are numbered (index j) 0..239 above the axis of rotation and
// 240..479 below the axis of rotation.

// The subtraction (i, j) - (iRotationAxis, jRotationAxis) moves the axis of
// rotation from (i, j) to (iRotationAxis, jRotationAxis), which is the
// center of the bitmap in this implementation.

jPrime := 2*(j - jRotationAxis) + 1;

FOR i := BitmapRotated.Width-1 DOWNTO 0 DO
BEGIN

iPrime := 2*(i - iRotationAxis) + 1;

// Rotate (iPrime, jPrime) to location of desired pixel
// Note: There is negligible difference between floating point and
// scaled integer arithmetic here, so keep the math simple (and readable).
iPrimeRotated := ROUND(iPrime * CosTheta - jPrime * sinTheta);
jPrimeRotated := ROUND(iPrime * sinTheta + jPrime * cosTheta);

// Transform back to pixel coordinates of image, including translation
// of origin from axis of rotation to origin of image.
iOriginal := (iPrimeRotated - 1) DIV 2 + iRotationAxis;
jOriginal := (jPrimeRotated - 1) DIV 2 + jRotationAxis;

// 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;
Delta := GetTickCount - StartTime; // "stop" the clock
LabelRotateTime.Caption := 'Rotation Time = ' + IntToStr(Delta) + ' ms';

ImageRotated.Picture.Graphic := BitmapRotated

END {RotateImage};


procedure TFormRotateScanLine.CheckBoxStretchClick(Sender: TObject);
begin
ImageOriginal.Stretch := CheckBoxStretch.Checked;
ImageRotated.Stretch := CheckBoxStretch.Checked
end;

procedure TFormRotateScanLine.ButtonSaveRotatedClick(Sender: TObject);
begin
IF SavePictureDialog.Execute
THEN BitmapRotated.SaveToFile(SavePictureDialog.Filename)
end;

end.

0 komentar:

Posting Komentar