当前位置: 首页 > article >正文

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;

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

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


http://www.kler.cn/a/549195.html

相关文章:

  • web的分离不分离:前后端分离与不分离全面分析
  • Java 运算符
  • ElasticSearch映射分词
  • Linux自学day18-二叉树、哈希表、常见的排序与查找算法
  • 【信息学奥赛一本通 C++题解】1288:三角形最佳路径问题
  • PAT乙级真题 — 1084 外观数列(java)
  • python 视频处理库moviepy 设置字幕
  • 微信小程序markdown转换为wxml(uniapp开发)
  • 使用 MySQL 从 JSON 字符串提取数据
  • Blazor-设置组件焦点
  • 记忆力训练day19
  • 【Python】错误异常
  • PHP基础部分
  • HTTP、HTTPS区别可靠性及POST为什么比GET安全的探讨
  • 光化学腐蚀法制作DIY钢网的制作流程
  • qt:对象树,窗口坐标,信号与槽
  • 【网络】协议与网络版计算器
  • BMS项目-面试及答疑整理
  • linux--关于linux文件IO(2) open、read、lseek、stat
  • C#中的动态类型用法总结带演示代码