怎么调用api函数实现图象旋转90度,180度等。(急用)(100分)

  • 主题发起人 主题发起人 flyoverXml
  • 开始时间 开始时间
F

flyoverXml

Unregistered / Unconfirmed
GUEST, unregistred user!
给我api函数名,最好能说明然后使用,谢谢
 
有这样的api吗?
 
好象有的。

如果自己写算法,对象素进行操作,速度实在太慢了啊。
 
不用api,
var
I, J: Integer;
BmpS, BmpD: TBitmap;
begin
BmpS := TBitmap.Create;
BmpD := TBitmap.Create;
BmpS.Assign(Image1.Picture.Graphic);
BmpD.Height := Image1.Picture.Width;
BmpD.Width := Image1.Picture.Height;
for I := 0 to Image1.Height do
for J := 0 to Image1.Width do
begin
if CheckBox1.Checked then
BmpD.Canvas.Pixels[(-I + Image1.Height), J] := BmpS.Canvas.Pixels[J, I]
else
BmpD.Canvas.Pixels[I, Image1.Width- J] := BmpS.Canvas.Pixels[J, I];
end;
Image1.Picture.Bitmap.Assign(BmpD); {}
end;

copy others[:D]
 
好像没有哦
自己写算法对scanline操作速度不慢呀
 
用SCANLINE,DELPHI中有例子!·
 
嘿嘿,
不是不会慢,是慢得离奇啊。
转90度要10s钟也。。

而且如果上面算法不做处理的话,图片会越来越小(小到一定程度就不会小了。)。
 
--->是慢得离奇啊。
可以看看慢得离奇的代码吗? (老实说, 要做到慢的离奇还真要一定功力呢)
 
to pearl:
下面有两种方法实现(嘿嘿,我想你应该能看得懂吧,:) ):

procedure Tbigform.roundtoround();
var
i,n,k:integer;
begin

bufferImage.Canvas.Brush.Color:=clblack;
bufferImage.Canvas.FillRect(rect(0,0,bufferImage.width,bufferImage.height));
bufferImage.height:=sourceImage.width;
bufferImage.width:=sourceImage.height;
n:=bigImage.width;
for k:=0 to bigImage.height do
begin
for i:=0 to bigImage.width do
begin
{ with rect1 do
begin
left:=k;
top:=i;
right:=k+1;
bottom:=i+1;
end;
with rect2 do
begin
left:=n-i-1;
top:=k;
right:=n-i;
bottom:=k-1;
end;
bufferImage.canvas.copyrect(rect2,SourceImage.canvas,rect1); }//方法一

bufferImage.Canvas.Pixels[(-k + bigImage.Height), i] := SourceImage.Canvas.Pixels[i, k]//方法二;

end;
end;
sourceImage.Picture:=bufferImage.Picture;

end;
两种算法的时间差不多离奇。
 
那你哪里用到scanline啦? 我怎么看不出?
 
先写一段180度的吧, 这个简单。 代码没优化过, 不过我想速度至少是你代码的10倍(也许谦虚了)
90度的有空再写。 我要去玩了[:)]
假设你的图片是24位位图
var
tmp: TBitmap
i, l: Integer;
begin
tmp := tbitmap.create;
tmp.pixelformat := pf24bit;
tmp.width := source.width;
tmp.height := source.height;
l := tmp.width * 3;
for i := 0 to tmp.height - 1 do
move(pchar(source.scanline[tmp.height-i-1])^, pchar(tmp.scanline)^, l);
source.assign(tmp);
tmp.free;
end;
 
卷兄曾经回答过这个问题
并有程序,你可以查找一下
 
type
EInvalidPixelFormat = class(Exception);

const
BitsPerByte = 8;


function GetPixelSize(aBitmap: TBitmap): integer;
var
nBitCount, nMultiplier: integer;
begin
case aBitmap.PixelFormat of
pfDevice:
begin
nBitCount := GetDeviceCaps(aBitmap.Canvas.Handle, BITSPIXEL);
nMultiplier := nBitCount div BitsPerByte;
if (nBitCount mod BitsPerByte)>0 then
Inc(nMultiplier);
end;
pf1bit: nMultiplier := 1;
pf4bit: nMultiplier := 1;
pf8bit: nMultiplier := 1;
pf15bit: nMultiplier := 2;
pf16bit: nMultiplier := 2;
pf24bit: nMultiplier := 3;
pf32bit: nMultiplier := 4;
else raise EInvalidPixelFormat.Create('Bitmap pixelformat is unknown.');
end;
Result := nMultiplier;
end;

procedure ImageRotate90(aBitmap: TBitmap);
var
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;

procedure TForm1.Button1Click(Sender: TObject);
begin
ImageRotate90(Image1.Picture.Bitmap);
end;
这是卷大侠招呼过的,绝对好用,而且不慢(是不慢,不是较快),粘贴就能用了
 
就是这个程序
xiaocai厉害
 
这个程序很快,旋转如果用pixels则太失败了
 
to xiaocai:

怎么可能粘贴就能用了?
能不能注解一下啊,我看起来很痛苦啊,
先注解一下好吗,谢谢
 
to pearl:
解释一下,行吗?
move(pchar(source.scanline[tmp.height-i-1])^, pchar(tmp.scanline)^, l);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~为什么是l呢?
这个返回值是指针类型啊,pchar()字符指针指向什么啊?

不懂,请解释,谢谢。
 
to xiaocai:
不好意思,刚才没有仔细看你是函数调用,原来是传递参数的。

我测试的时候是 用,
ImageRotate90(SourceImage.Picture.Bitmap);
showmessage('ok');

一点击就ok显示出来了,执行速度是很快,但是什么都没有旋转,可能你的函数什么地方写错了,
能在仔细 看一下你写的函数和关键的地方解释一下吗?
 
to flyoverXml:
你问的这个问题其实牵涉到move过程的参数和实现。
procedure Move(const Source; var Dest; Count: Integer);
先回答简单的:
为什么 Count 要用l: 24位位图中每像素的颜色是由3个字节组成, 而move过程能处理的只能是字节, 所以这里Count=l(l=图像宽度*3)

为什么用PChar(xxxx)^:
注意函数定义:
1、Source和Dest都是无类型的, 也就是说,编译器生成代码时, 会传递你输入参数的首地址而不是具体参数的值
2、ScanLine是个无类型指针, 如果直接将这个值做为move的参数传递的话, 具体生成代码是, 传递的并不是你所希望的scanline所指向的内存。
而是scanline这个指针自己所在的内存。 因此我们必须把scanline指向的地方传递给move过程。
由于对无类型指针delphi中不能用Pointer^这种表现形式(语法检查通不过),所以必须把它强制转换成一种特定的指针形式, 用pchar只不过我觉得顺手而已[:)],你可以用任何指针类型(比如PInteger, 甚至PGUID)。
 
后退
顶部