【问题标题】:Why did CopyRect Flipped the second image in delphi 10.3?为什么CopyRect在delphi 10.3中翻转了第二张图片?
【发布时间】:2019-09-08 15:42:45
【问题描述】:

我想对我的页面进行截图并将结果放入位图,因为页面上有一个滚动条,我必须截取几张截图,我想合并这些位图。

如果使用此代码截屏并保存:Take a screenshot of a particular area in Delphi 7

我使用代码从这个页面合并它们http://www.delphigroups.info/2/8/309463.html

如果我直接复制它,它将导致使用第一个图像,第二个是白色矩形。所以我尝试对其进行一些更改,现在我将两个图像放在一个文件中。

这是我用来连接位图的代码:

    function ConcatenateBitmaps(const MainBitmap: TBitmap; const BitmapToAdd: 
    TBitmap): TBitmap;
    begin
      Result := MainBitmap;

      If BitmapToAdd.Width > MainBitmap.Width then
        Result.Width := BitmapToAdd.Width;

      Result.Height := MainBitmap.Height + MainBitmap.Height;
      Result.Canvas.CopyRect(
        Rect(0,MainBitmap.Height,BitmapToAdd.Width,BitmapToAdd.Height),
        BitmapToAdd.Canvas,
        Rect(0,0,BitmapToAdd.Width,BitmapToAdd.Height)
      );
    end;

问题是第二张图像被垂直和水平翻转;

我在这里做错了什么?

编辑: 结果的一个例子,第一个图像是好的,第二个图像被翻转:

正如我现在看到的,我的描述是错误的,它是水平镜像,垂直翻转

【问题讨论】:

  • 代码至少有 2 个问题:1) Rect 需要 2 个点的坐标,而不是宽度和高度 2) 在 Result := MainBitmap; 之后,两个变量都指向同一个对象,所以改变尺寸的Result 更改MainBitmap 的尺寸

标签: delphi canvas bitmap


【解决方案1】:

原因和快速修复:

问题出在这部分:

Rect(0,MainBitmap.Height,BitmapToAdd.Width,BitmapToAdd.Height)

您创建一个矩形,其中top 是生成图像的总高度,底部是要添加的位图的高度。所以这个矩形基本上是倒置的(它的底部在它的顶部之上)。

而且它也可能变形了,因为这个矩形的高度不是要添加的位图的高度。

快速修复将是:

Rect(0,Result.Height- BitmapToAdd.Height,BitmapToAdd.Width,Result.Height)

其他问题和困惑:

但我认为造成您困惑的原因是因为您认为 Result 和 MainBitmap 是两个不同的位图,而实际上它们都是对同一个位图的引用。您在开始时所做的分配只是复制引用,而不是实际的 TBitmap 对象。

此外,您混淆了“高度”和“底部”。 TRect 希望您设置顶部和底部坐标,而不是顶部和高度。这与上一个问题一起,不仅导致位图颠倒,而且会被拉伸,并部分覆盖以前的图像。添加的图片越多,效果就越清晰。

我个人认为在这种情况下修改现有位图效率更高,主要是因为否则您必须一直清理旧位图,而且您有一个神奇地创建位图的功能。您会遇到位图对象的所有权问题,随之而来的是内存泄漏的风险,这是不好的,尤其是在处理大位图时。

我建议的版本:

所以,我将把它变成一个过程,其中通过添加第二个位图来修改第一个位图。

在下面的版本中,我还使用了Canvas.ClipRect,它用于位图,本质上是位图的边界矩形。然后我使用OffsetRect 来“移动”这个矩形(增加它的顶部 Y 和底部 Y)。

通过在单独的变量中执行此操作,与我上面介绍的快速修复相比,您可以获得一个相对干净的版本,因为您可以在实际修改之前使用 MainBitmap 的尺寸。

procedure AppendBitmap(const MainBitmap: TBitmap; const BitmapToAdd:
TBitmap);
var
  TargetRect: TRect;
begin
  // Widen the main bitmap if needed
  if BitmapToAdd.Width > MainBitmap.Width then
    MainBitmap.Width := BitmapToAdd.Width;

  // Set TargetRect to the right size
  TargetRect := BitmapToAdd.Canvas.ClipRect;
  // And then to the right position
  OffsetRect(TargetRect, 0, MainBitmap.Height);

  // Make room for the bitmap to add
  MainBitmap.Height := MainBitmap.Height + BitmapToAdd.Height;

  // Draw it in the created space
  MainBitmap.Canvas.CopyRect(
    TargetRect,
    BitmapToAdd.Canvas,
    BitmapToAdd.Canvas.ClipRect
  );
end;

如果您愿意,您可以使用原始签名创建一个包装函数,创建主图像的副本并将其返回。但请注意,MainBitmap 和此函数的结果不再是同一个位图,您必须确保在完成后正确释放它们。

function ConcatenateBitmaps(const MainBitmap: TBitmap; const BitmapToAdd:
TBitmap): TBitmap;
begin
  Result := TBitmap.Create;
  Result.Assign(MainBitmap);
  AppendBitmap(Result, BitmapToAdd);
end;

PS:我喜欢这样的问题,我可以从中学到一些东西。我从来没有意识到你可以通过翻转传递给 CopyRect 的矩形来翻转图像。 :D

【讨论】:

  • 经过一番额外的努力后,我用与您的快速修复类似的方法修复了它。但最后你建议的版本确实更好。很高兴看到你喜欢它,谢谢你的详细解释!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多