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;

这个是我个人测试内存开销最小的一个,速度和第二个相当。几乎肉眼看不到延迟。

也是我最后采纳的一个方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值