图形旋转问题?(100分)

  • 主题发起人 主题发起人 liyipeng
  • 开始时间 开始时间
L

liyipeng

Unregistered / Unconfirmed
GUEST, unregistred user!
如何编程实现,让picturebox中显示的图片可以旋转,比如旋转90度?
 
用imgedit(activeX 控件)试一下。
 
BOOL StretchBlt(

HDC hdcDest, // handle of destination device context
int nXOriginDest, // x-coordinate of upper-left corner of dest. rect.
int nYOriginDest, // y-coordinate of upper-left corner of dest. rect.
int nWidthDest, // width of destination rectangle
int nHeightDest, // height of destination rectangle
HDC hdcSrc, // handle of source device context
int nXOriginSrc, // x-coordinate of upper-left corner of source rectangle
int nYOriginSrc, // y-coordinate of upper-left corner of source rectangle
int nWidthSrc, // width of source rectangle
int nHeightSrc, // height of source rectangle
DWORD dwRop // raster operation code
);
 
好多方法,查查别人已经问过的问题
 
procedure ImageRotate90(aBitmap: TBitmap); //逆时针旋转90,速度很快
nIdx, nOfs,
x, y, i, nMultiplier: integer;
nMemWidth, nMemHeight, nMemSize, nScanLineSize: LongInt;
aScnLnBuffer: PChar;
aScanLine: PByteArray;
begin
nMultiplier := GetPixelSize(ABitmap);
nMemWidth := aBitmap.Height;
nMemHeight := aBitmap.Width;
nMemSize := nMemWidth * nMemHeight * nMultiplier;
GetMem(aScnLnBuffer, nMemSize);
try
nScanLineSize := aBitmap.Width * nMultiplier;
GetMem(aScanLine, nScanLineSize);
try
for y := 0 to aBitmap.Height - 1 do
begin
Move(aBitmap.ScanLine[y]^, aScanLine^, nScanLineSize);
for x := 0 to aBitmap.Width - 1 do
begin
nIdx := ((aBitmap.Width - 1) - x) * nMultiplier;
nOfs := (x * nMemWidth * nMultiplier) + (y * nMultiplier);
for i := 0 to nMultiplier - 1 do
Byte(aScnLnBuffer[nOfs + i]) := aScanLine[nIdx + i];
end;
end;
aBitmap.Height := nMemHeight; //¿íºÍ¸ß½»»»¿ªÊ¼ÄæʱÕëÐýת
aBitmap.Width := nMemWidth;
for y := 0 to nMemHeight - 1 do
begin
nOfs := y * nMemWidth * nMultiplier;
Move((@(aScnLnBuffer[nOfs]))^, aBitmap.ScanLine[y]^, nMemWidth *
nMultiplier);
end;
finally
FreeMem(aScanLine, nScanLineSize);
end;
finally
FreeMem(aScnLnBuffer, nMemSize);
end;
end;
 
huazai你好,我是个delphi的初学者,所以还有点问题问问你,就是你的旋转函数,
能不能告诉一下如何调用执行。比如在一个窗体上放置一个image控件后,如何设置属
性,如何使用你的函数等等,谢谢!
 
childform.Image1.Picture.Bitmap.PixelFormat := pf24bit;
ImageRotate90(childform.Image1.Picture.Bitmap);
这样就可以了,给分吧
 
procedure TForm1.BitBtn1Click(Sender: TObject);//90度
var
color:TColor;
i,j:integer;
begin
Image2.Width:=Image1.Height;
Image2.Height:=Image1.Width;
for i:=0 to Image1.Width do
for j:=0 to Image1.Height do
begin
Image2.Canvas.Pixels[j,i]:=Image1.Canvas.Pixels[i,j];
end;
end;

procedure TForm1.BitBtn2Click(Sender: TObject);//180度
var
color:TColor;
i,j:integer;
begin
Image2.Height:=Image1.Height;
Image2.Width:=Image1.Width;
for i:=0 to Image1.Width do
for j:=0 to Image1.Height do
begin
Image2.Canvas.Pixels[i,Image2.Height-j]:=Image1.Canvas.Pixels[i,j];
end;
end;
任意角度的旋转,需要做数据变换,数学基本知识,以上两个只是演示,速度很慢,较快的办法不用Image,而是使用TBitmap,也就是先建立临时Bitmap,
 
我有任意角旋转的代码,比较简单,我得email:huazai@zju.edu.cn
 
huazai,能不能給我一份任意角度旋轉的代碼,Donald_sh@etang.com,謝謝
 
我给你一份任意角度旋轉的代碼,别忘了加分哦!

//旋转90度
procedure Rotate90(const Bitmap:TBitmap);
var
i,j:Integer;
rowIn,rowOut:pRGBTriple;
Bmp:TBitmap;
Width,Height:Integer;
begin
Bmp:=TBitmap.Create;
Bmp.Width := Bitmap.Height;
Bmp.Height := Bitmap.Width;
Bmp.PixelFormat := pf24bit;
Width:=Bitmap.Width-1;
Height:=Bitmap.Height-1;
for j := 0 to Height do
begin
rowIn := Bitmap.ScanLine[j];
for i := 0 to Width do
begin
rowOut := Bmp.ScanLine;
Inc(rowOut,Height - j);
rowOut^ := rowIn^;
Inc(rowIn);
end;
end;
Bitmap.Assign(Bmp);
end;

//旋转180度
procedure Rotate180(const Bitmap:TBitmap);
var
i,j:Integer;
rowIn,rowOut:pRGBTriple;
Bmp:TBitmap;
Width,Height:Integer;
begin
Bmp:=TBitmap.Create;
Bmp.Width := Bitmap.Width;
Bmp.Height := Bitmap.Height;
Bmp.PixelFormat := pf24bit;
Width:=Bitmap.Width-1;
Height:=Bitmap.Height-1;
for j := 0 to Height do
begin
rowIn := Bitmap.ScanLine[j];
for i := 0 to Width do
begin
rowOut := Bmp.ScanLine[Height - j];
Inc(rowOut,Width - i);
rowOut^ := rowIn^;
Inc(rowIn);
end;
end;
Bitmap.Assign(Bmp);
end;

//旋转270度
procedure Rotate270(const Bitmap:TBitmap);
var
i,j:Integer;
rowIn,rowOut:pRGBTriple;
Bmp:TBitmap;
Width,Height:Integer;
begin
Bmp:=TBitmap.Create;
Bmp.Width := Bitmap.Height;
Bmp.Height := Bitmap.Width;
Bmp.PixelFormat := pf24bit;
Width:=Bitmap.Width-1;
Height:=Bitmap.Height-1;
for j := 0 to Height do
begin
rowIn := Bitmap.ScanLine[j];
for i := 0 to Width do
begin
rowOut := Bmp.ScanLine[Width - i];
Inc(rowOut,j);
rowOut^ := rowIn^;
Inc(rowIn);
end;
end;
Bitmap.Assign(Bmp);
end;

前面为判断部分,如果是90,180,270这类特殊角度,将调用上面的代码,这样效率更高!

//任意角度
function RotateBitmap(Bitmap:TBitmap;Angle:Integer;BackColor:TColor):TBitmap;
var
i,j,iOriginal,jOriginal,CosPoint,SinPoint : integer;
RowOriginal,RowRotated : pRGBTriple;
SinTheta,CosTheta : Extended;
AngleAdd : integer;
begin
Result:=TBitmap.Create;
Result.PixelFormat := pf24bit;
Result.Canvas.Brush.Color:=BackColor;
Angle:=Angle Mod 360;
if Angle<0 then Angle:=360-Abs(Angle);
if Angle=0 then
Result.Assign(Bitmap)
else if Angle=90 then
begin
Result.Assign(Bitmap);
Rotate90(Result);//如果是旋转90度,直接调用上面的代码
end
else if (Angle>90) and (Angle<180) then
begin
AngleAdd:=90;
Angle:=Angle-AngleAdd;
end
else if Angle=180 then
begin
Result.Assign(Bitmap);
Rotate180(Result);//如果是旋转180度,直接调用上面的过程
end
else if (Angle>180) and (Angle<270) then
begin
AngleAdd:=180;
Angle:=Angle-AngleAdd;
end
else if Angle=270 then
begin
Result.Assign(Bitmap);
Rotate270(Result);//如果是旋转270度,直接调用上面的过程
end
else if (Angle>270) and (Angle<360) then
begin
AngleAdd:=270;
Angle:=Angle-AngleAdd;
end
else
AngleAdd:=0;
if (Angle>0) and (Angle<90) then
begin
SinCos((Angle + AngleAdd) * Pi / 180, SinTheta, CosTheta);
if (SinTheta * CosTheta) < 0 then
begin
Result.Width := Round(Abs(Bitmap.Width * CosTheta - Bitmap.Height * SinTheta));
Result.Height := Round(Abs(Bitmap.Width * SinTheta - Bitmap.Height * CosTheta));
end
else
begin
Result.Width := Round(Abs(Bitmap.Width * CosTheta + Bitmap.Height * SinTheta));
Result.Height := Round(Abs(Bitmap.Width * SinTheta + Bitmap.Height * CosTheta));
end;
CosTheta:=Abs(CosTheta);
SinTheta:=Abs(SinTheta);
if (AngleAdd=0) or (AngleAdd=180) then
begin
CosPoint:=Round(Bitmap.Height*CosTheta);
SinPoint:=Round(Bitmap.Height*SinTheta);
end
else
begin
SinPoint:=Round(Bitmap.Width*CosTheta);
CosPoint:=Round(Bitmap.Width*SinTheta);
end;
for j := 0 to Result.Height-1 do
begin
RowRotated := Result.Scanline[j];
for i := 0 to Result.Width-1 do
begin
Case AngleAdd of
0:
begin
jOriginal := Round((j+1)*CosTheta-(i+1-SinPoint)*SinTheta)-1;
iOriginal := Round((i+1)*CosTheta-(CosPoint-j-1)*SinTheta)-1;
end;
90:
begin
iOriginal := Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta)-1;
jOriginal := Bitmap.Height-Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta);
end;
180:
begin
jOriginal := Bitmap.Height-Round((j+1)*CosTheta-(i+1-SinPoint)*SinTheta);
iOriginal := Bitmap.Width-Round((i+1)*CosTheta-(CosPoint-j-1)*SinTheta);
end;
270:
begin
iOriginal := Bitmap.Width-Round((j+1)*SinTheta-(i+1-SinPoint)*CosTheta);
jOriginal := Round((i+1)*SinTheta-(CosPoint-j-1)*CosTheta)-1;
end;
end;
if (iOriginal >= 0) and (iOriginal <= Bitmap.Width-1)and
(jOriginal >= 0) and (jOriginal <= Bitmap.Height-1)
then
begin
RowOriginal := Bitmap.Scanline[jOriginal];
Inc(RowOriginal,iOriginal);
RowRotated^ := RowOriginal^;
Inc(RowRotated);
end
else
begin
Inc(RowRotated);
end;
end;
end;
end;
end;



 
function RotateBitmap(Bitmap:TBitmap;Angle:Integer;BackColor:TColor):TBitmap;
好像有问题
 
这是一段可以旋转任意角度的代码:
///////////////////////////////// /
////// designed by billy_phd /////
//////////////////////////////////
unit urotate;

interface

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

type
Trgbarray = array[0..32767]of trgbtriple;
prgbarray=^Trgbarray;

TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
OpenDialog1: TOpenDialog;
SpinEdit1: TSpinEdit;
SpinEdit2: TSpinEdit;
Image2: TImage;
procedure Button1Click(Sender: TObject);
procedure rotatebitmap;
procedure SpinEdit1Change(Sender: TObject);
procedure SpinEdit2Change(Sender: TObject);
private
{ Private declarations }
rotatedbitmap:tbitmap;
sourcebitmap:tbitmap;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
procedure tform1.rotatebitmap;
var rowrotated,roworiginal:prgbarray;
i,j,ioriginal,joriginal,jprime,iprime:integer;
sinthed,costhed:double;
thed:double;
begin
rotatedbitmap:=tbitmap.Create;
rotatedbitmap.Width:=sourcebitmap.Width;
rotatedbitmap.Height:=sourcebitmap.Height;
rotatedbitmap.PixelFormat:=pf24bit;

thed:=-(spinedit1.Value+spinedit2.Value/100)*pi/180;
sinthed:=sin(thed);
costhed:=cos(thed);

//through my test if i use :for j:=rotatedbitmap.height-1 downto 0 do ;has the
//same result;
for j:=0 to rotatedbitmap.Height-1 do
begin
rowrotated:=rotatedbitmap.ScanLine[j];
jprime:=2*j+1;
for i:=0 to rotatedbitmap.Width-1 do
begin
iprime:=2*i+1;

//if ioriginal:=-(round(iprime*costhed-jprime*sinthed)-1) div 2 ;
//joriginal:=(round(jprime*costhed+iprime*sinthed)-1) div 2 ;we
//can get another graphics,so we can change the diaplay of rotation
//by choosing the proper mathematical function

ioriginal:=(round(iprime*costhed-jprime*sinthed)-1) div 2;
joriginal:=(round(jprime*costhed+iprime*sinthed)-1) div 2 ;

if (ioriginal>=0) and (ioriginal<=rotatedbitmap.Width-1) and(joriginal>=0) and(joriginal<=rotatedbitmap.Height-1)
then begin
roworiginal:=sourcebitmap.ScanLine[joriginal];
rowrotated:=roworiginal[ioriginal];
end
else
begin
rowrotated.rgbtBlue:=255;
rowrotated.rgbtGreen:=0;
rowrotated.rgbtRed:=0;
end;
end;
end;
image1.Picture.Graphic:=rotatedbitmap;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
sourcebitmap:=tbitmap.Create;
if opendialog1.Execute then
sourcebitmap.LoadFromFile(opendialog1.FileName);
image2.Picture.Graphic:=sourcebitmap;
rotatebitmap;

end;

procedure TForm1.SpinEdit1Change(Sender: TObject);
begin
rotatebitmap;
end;

procedure TForm1.SpinEdit2Change(Sender: TObject);
begin
rotatebitmap;
end;

end.
别忘了加分哦
 
to liyipeng:
我给的答案不满意吗?有问题可以讨论,知道你接受答案为止[:D]
 
用TIMER不断旋转时会上下跳动,
 
后退
顶部