为什么 CopyRect 在 delphi 10.3 中翻转了第二张图片?

Why did CopyRect Flipped the second image in delphi 10.3?

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

如果使用此代码截屏并保存:

我使用代码从这个页面合并它们 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;

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

我做错了什么?

编辑: 结果的一个例子,第一张图不错,第二张图翻转了:

现在看来,我的描述是错误的,水平镜像,垂直翻转

原因和快速修复:

问题出在这部分:

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

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

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

快速修复是:

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

其他问题和困惑:

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

此外,您混淆了 'height' 和 'bottom'。 TRect 希望您设置顶部和底部坐标,而不是顶部和高度。这一点,连同上一个问题,不仅导致位图倒置,而且会被拉伸,部分覆盖之前的图像。添加的图片越多,效果越明显。

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

我建议的版本:

因此,我只想将其作为一个过程,其中通过向其中添加第二个位图来修改第一个位图。

在下面的版本中,我还使用了Canvas.ClipRect,这是针对位图的,本质上是位图的外接矩形。然后我使用 OffsetRect 到 'move' 这个矩形(增加它的顶部 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;

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

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

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