Lazarus 旋转图片(TImage、TBitmap)
想用Lazarus旋转图片,在QT上轻松就能做到的事情,在lazarus上却没有标准实现,只能用其他方式。找了挺多帖子,有这三种有效的方案。
第一种:不依赖其他控件
procedure TMainForm.RotateImage(Bitmap: TBitmap);
var
NewBitmap: TBitmap;
X, Y: integer;
begin
// 创建新的位图对象,用于存储旋转后的图片
NewBitmap := TBitmap.Create;
try
// 设置新位图的宽度和高度,这里交换原位图的宽度和高度
NewBitmap.Width := Bitmap.Height;
NewBitmap.Height := Bitmap.Width;
// 遍历原位图的每个像素
for Y := 0 to Bitmap.Height - 1 do
for X := 0 to Bitmap.Width - 1 do
// 将原位图的像素按照旋转规则复制到新位图中
NewBitmap.Canvas.Pixels[Bitmap.Height - Y - 1, X] := Bitmap.Canvas.Pixels[X, Y];
// 清空原位图
Bitmap.Canvas.FillRect(0, 0, Bitmap.Width, Bitmap.Height);
// 复制旋转后的位图到原位图
Bitmap.Assign(NewBitmap);
finally
// 释放新位图对象
NewBitmap.Free;
end;
end;
问题是,速度太慢、内存开销较大,一张1080P的图片运行一次要耗费2秒钟左右,太慢了。
第二种:依赖 TBGRABitmap,使用 TBGRAAffineBitmapTransform 进行变换
procedure TMainForm.RotateImage;
var
BGRAImg: TBGRABitmap;
Affine: TBGRAAffineBitmapTransform;
Temp: TBGRABitmap;
OldWidth, OldHeight: integer;
begin
// 检查 Image1 中是否有图片
if Image1.Picture.Bitmap = nil then
Exit;
OldWidth := Image1.Picture.Bitmap.Width;
OldHeight := Image1.Picture.Bitmap.Height;
// 创建 TBGRABitmap 对象,并将 Image1 中的图片转换为 TBGRABitmap
BGRAImg := TBGRABitmap.Create(Image1.Picture.Bitmap);
try
// 创建仿射变换对象
Affine := TBGRAAffineBitmapTransform.Create(BGRAImg);
try
// 先将图像平移到原点
Affine.Translate(-BGRAImg.Width div 2, -BGRAImg.Height div 2);
// 向右旋转 90 度
Affine.RotateDeg(90);
// 再平移回原来的位置
Affine.Translate(BGRAImg.Height div 2, BGRAImg.Width div 2);
// 创建临时的 TBGRABitmap 对象,用于存储旋转后的图像
Temp := TBGRABitmap.Create(BGRAImg.Height, BGRAImg.Width, BGRAWhite);
try
// 使用仿射变换填充临时图像
Temp.FillPolyAntialias([PointF(0, 0), PointF(Temp.Width, 0),
PointF(Temp.Width, Temp.Height), PointF(0, Temp.Height)], Affine);
Image1.Picture.Clear;
// 调整 Image1 控件的大小以适应旋转后的图片
Image1.Width := OldHeight;
Image1.Height := OldWidth;
// 将旋转后的图像用Image1绘制出
Temp.Draw(Image1.Canvas, 0, 0);
finally
// 释放临时图像对象
Temp.Free;
end;
finally
// 释放仿射变换对象
Affine.Free;
end;
finally
// 释放 TBGRABitmap 对象
BGRAImg.Free;
end;
end;
尤其要注意:uses BGRATransform;
速度很快,和第一个比快了30倍左右。
第三种,使用 TBGRABitmap
procedure TMainForm.RotateImage;
var
BGRAImg: TBGRABitmap;
OldWidth, OldHeight: integer;
begin
// 检查 Image1 中是否有图片
if Image1.Picture.Bitmap = nil then
Exit;
// 记录原始图片的宽度和高度
OldWidth := Image1.Picture.Bitmap.Width;
OldHeight := Image1.Picture.Bitmap.Height;
// 创建 TBGRABitmap 对象,并将 Image1 中的图片转换为 TBGRABitmap
BGRAImg := TBGRABitmap.Create(Image1.Picture.Bitmap);
try
if RotationDeg = 1 then
begin
BGRAReplace(BGRAImg, BGRAImg.RotateCW()); //右转90度
end;
if RotationDeg = 2 then
begin
BGRAReplace(BGRAImg, BGRAImg.RotateUD()); //翻转180度
end;
if RotationDeg = 3 then
begin
BGRAReplace(BGRAImg, BGRAImg.RotateCCW()); //左转90度
end;
// 清空 Image1 原有的图片
Image1.Picture.Clear;
// 调整 Image1 控件的大小以适应旋转后的图片
if (RotationDeg = 1) or (RotationDeg = 3) then
begin
Image1.Width := OldHeight;
Image1.Height := OldWidth;
end;
if (RotationDeg = 2) or (RotationDeg = 0) then
begin
Image1.Width := OldWidth;
Image1.Height := OldHeight;
end;
BGRAImg.Draw(Image1.Canvas, 0, 0);
finally
// 释放 TBGRABitmap 对象
BGRAImg.Free;
end;
end;
这个是我个人测试内存开销最小的一个,速度和第二个相当。几乎肉眼看不到延迟。
也是我最后采纳的一个方案。