从网上搜到的,原链接没有说明原始出处, 感谢原作者和转载者
代码中的注释是根据自己的理解改写的
delphi 图像旋转 - 酷联云视 - 博客园 (cnblogs.com)
一开始是用canvas.pixel处理, 实在是太慢, 又搜到了这个scanline方式的, 实测逆时针90度旋转好用, 就又改了一个顺时针90度旋转的, 原文是针对正常的24位的bmp图, 这个已经修改为用于8位bmp图形文件
(对delphi一知半解, 最后是试出来的, 前后花了近两天时间;中间还被迫使用三次逆时针90度来代替顺时针90度, 实在是汗... 好在最后还是能用了)
procedure rotate2(bmpfilename: PChar); stdcall; //逆时针旋转
var
sourcebmp: Graphics.TBitmap;
nIdx, nOfs, x, y, i, nMultiplier: integer;
nMemWidth, nMemHeight, nMemSize, nScanLineSize: LongInt;
aScnLnBuffer: PChar;
aScanLine: PByteArray;
begin
sourcebmp := Graphics.TBitmap.Create();
sourcebmp.LoadFromFile(bmpfilename);
nMultiplier := 1;
nMemWidth := sourcebmp.Height;
nMemHeight := sourcebmp.Width;
//实际需要内存大小
nMemSize := nMemWidth * nMemHeight * nMultiplier;
//开辟内存
GetMem(aScnLnBuffer, nMemSize);
try
//Scanline的长度
nScanLineSize := sourcebmp.Width * nMultiplier;
//为ScanLine分配内存
GetMem(aScanLine, nScanLineSize);
try
//从sourcebmp, 通过byte数组 向缓冲区导入数据
for y := 0 to sourcebmp.Height - 1 do
begin
//1.把source中的行, 逐行复制到byte数组中
Move(sourcebmp.ScanLine[y]^, aScanLine^, nScanLineSize);
for x := 0 to sourcebmp.Width - 1 do
begin//2.宽和高交换,逆时针旋转
nIdx := ((sourcebmp.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;
sourcebmp.Height := nMemHeight;
sourcebmp.Width := nMemWidth;
for y := 0 to nMemHeight - 1 do
begin
//缓冲区的数据写回sourcebmp
nOfs := y * nMemWidth * nMultiplier;
Move((@(aScnLnBuffer[nOfs]))^, sourcebmp.ScanLine[y]^, nMemWidth * nMultiplier);
end;
sourcebmp.SaveToFile(bmpfilename);
finally
//释放内存aScanLine
FreeMem(aScanLine, nScanLineSize);
end;
finally
//释放内存aScnLnBuffer
FreeMem(aScnLnBuffer, nMemSize);
end;
sourcebmp.Free;
end;
procedure rotate(bmpfilename: PChar); stdcall; //顺时针旋转
var
sourcebmp: Graphics.TBitmap;
nIdx, nOfs, x, y, i, nMultiplier: integer;
nMemWidth, nMemHeight, nMemSize, nScanLineSize: LongInt;
aScnLnBuffer: PChar;
aScanLine: PByteArray;
begin
sourcebmp := Graphics.TBitmap.Create();
sourcebmp.LoadFromFile(bmpfilename);
nMultiplier := 1;
nMemWidth := sourcebmp.Height;
nMemHeight := sourcebmp.Width;
//实际需要内存大小
nMemSize := nMemWidth * nMemHeight * nMultiplier;
//开辟内存
GetMem(aScnLnBuffer, nMemSize);
try
//Scanline的长度
nScanLineSize := sourcebmp.Width * nMultiplier;
//为ScanLine分配内存
GetMem(aScanLine, nScanLineSize);
try
//从sourcebmp, 通过byte数组 向缓冲区导入数据
for y := 0 to sourcebmp.Height - 1 do
begin
//1.把source中的行, 逐行复制到byte数组中
Move(sourcebmp.ScanLine[y]^, aScanLine^, nScanLineSize);
for x := 0 to sourcebmp.Width - 1 do
begin //2.宽和高交换,顺时针旋转
nIdx := x * nMultiplier;
nOfs := (x * nMemWidth * nMultiplier) + ((sourcebmp.Height - 1 - y) * nMultiplier);
for i := 0 to nMultiplier - 1 do
Byte(aScnLnBuffer[nOfs + i]) := aScanLine[nIdx + i];
end;
end;
//缓冲区的数据写回sourcebmp
sourcebmp.Height := nMemHeight;
sourcebmp.Width := nMemWidth;
for y := 0 to nMemHeight - 1 do
begin
//通过byte数组的方式, 逐行写回sourcebmp
nOfs := y * nMemWidth * nMultiplier;
Move((@(aScnLnBuffer[nOfs]))^, sourcebmp.ScanLine[y]^, nMemWidth * nMultiplier);
end;
sourcebmp.SaveToFile(bmpfilename);
finally
//释放内存aScanLine
FreeMem(aScanLine, nScanLineSize);
end;
finally
//释放内存aScnLnBuffer
FreeMem(aScnLnBuffer, nMemSize);
end;
sourcebmp.Free;
end;