如何使用firemonkey在选定区域裁剪位图?

Posted

技术标签:

【中文标题】如何使用firemonkey在选定区域裁剪位图?【英文标题】:How crop bitmap in selected area using firemonkey? 【发布时间】:2017-10-22 23:59:08 【问题描述】:

我需要为我的应用创建裁剪效果。我在 TImage 上有一个 TRectangle,当用户按下保存按钮时,我需要只复制 TRectangle 使用的区域。有什么方法可以只从 Image1.Bitmap 中剪切一个特定区域?我打印了一张图片以更好地说明我需要什么:

【问题讨论】:

你最好使用可以控制比例的画布。不要只使用任何随机的图像控件。如果是我,我会为此编写一个自定义控件。但这不会是一件非常微不足道的事情。 您使用的WrapMode 是什么?如果它是Tile 并且您的选择器覆盖了显示图像的多个图块怎么办? 裁剪过程如下: 1) 计算图像的缩放比例并将矩形边界转换为图像比例。 2) 创建一个 TBitmap 并将 CopyFromBitmap 与计算出的矩形一起使用。这会将 TImage 位图中的一个部分复制到新位图中。 3)将位图分配给您的 TImage 位图(如果这是您想要的)。 你能给我一个关于如何执行第 2 步的代码示例吗? 这个概念非常简单:在受控画布上绘制图像(您可以 100% 控制),然后进行简单的数学运算来确定比例。当然有很多资源如何在 Firemonkey 中提取图像的一部分。我用它们编写了我自己的矢量签名控件。对你来说更简单。但请不要指望我们会为您编写。 【参考方案1】:

这是一个适合我的示例:

procedure TForm1.Button1Click(Sender: TObject);
var
  Bmp: TBitmap;
  xScale, yScale: extended;
  iRect: TRect;
begin

  Bmp := TBitmap.Create;
  xScale := Image1.Bitmap.Width / Image1.Width;
  yScale := Image1.Bitmap.Height / Image1.Height;
  try
    Bmp.Width := round(Rectangle1.Width * xScale);
    Bmp.Height := round(Rectangle1.Height * yScale);
    iRect.Left := round(Rectangle1.Position.X * xScale);
    iRect.Top := round(Rectangle1.Position.Y * yScale);
    iRect.Width := round(Rectangle1.Width * xScale);
    iRect.Height := round(Rectangle1.Height * yScale);
    Bmp.CopyFromBitmap(Image1.Bitmap, iRect, 0, 0);
    Image2.Bitmap := Bmp
  finally
    Bmp.Free;
  end;
end;

我在这里假设Rectangle1Image1 作为它的Parent

否则您将需要考虑Position.XPosition.Y 属性的偏移量。

这是程序运行的结果:

【讨论】:

非常感谢,正是我需要的! 我在手机上试过你的解决方案,但在一些分辨率和比例不同的智能手机中......从选择中复制的图像不正确。为什么? 这个方法准确率很差,scale是Single,rect的X、Y、Heigh和Width都是Single,但是TRect要求的是Integer,这么多“轮”要转换代码更改裁剪区域的尺寸。我正在尝试使用 TCanvas 方法将 TImage 的画布绘制到 retangle 的 TCanvas,然后使用 makenapshot 从矩形中获取 TBitmap。但仍在尝试。 @Joao xScale 和 yScale 是扩展的,而不是单一的。坦率地说,我怀疑单曲的 mashine epsilon 5.96e-08 - 1.19e-07 在当前情况下真的很重要。当分辨率约为 10000000 - 100000000 像素时,可能会出现 1 px 错误。否则我想知道您是否可以为更高精度的处理指定确切的实际任务。 @asd-tm 不是关于类型精度,而是关于转换。扩展的四舍五入到整数会导致结果发生重大变化。我正在使用您的代码从 timage 中获取一个矩形,结果与裁剪区域不同,矩形区域的变化大于比例。【参考方案2】:

另一种方法:

var
  Tmp: TBitmap;
  Bmp: TBitmap;
  iRect: TRect;
begin
  Tmp := TBitmap.Create;
  Tmp := Image1.MakeScreenshot; //ignore the scale, so will F*ck the resolution, but resolve the scale issues
  Bmp := TBitmap.Create;
  try
    Bmp.Width := round(Rectangle1.Width);
    Bmp.Height := round(Rectangle1.Height);
    iRect.Left := round(Rectangle1.Position.X);
    iRect.Top := round(Rectangle1.Position.Y);
    iRect.Width := round(Rectangle1.Width);
    iRect.Height := round(Rectangle1.Height);
    Bmp.CopyFromBitmap(tmp, iRect, 0, 0);
    Image2.Bitmap := Bmp
  finally
    Tmp.Free;
    Bmp.Free;
  end;

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。

以上是关于如何使用firemonkey在选定区域裁剪位图?的主要内容,如果未能解决你的问题,请参考以下文章

如何裁剪矩形区域? [关闭]

如何在不裁剪的情况下查看矩形选框选定区域的大小?在 Photoshop CS 5 中

使用 Path 对象裁剪位图

如何在 iOS 中裁剪非矩形区域

Firemonkey (FMX) 位图和颜色

在位图上制作可调整的裁剪矩形