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

时间:2019-04-18 10:04:42

标签: delphi canvas bitmap

我想截取页面的截图并将结果放入位图,因为页面上有滚动条,所以我必须截取几个截屏,并且希望合并这些位图。

如果已使用此代码制作了屏幕截图并将其保存: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;

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

我在这里做什么错了?

编辑: 结果的一个例子,第一个图像是好的,第二个图像是翻转的: enter image description here

如我现在所见,我的描述是错误的,它在水平方向上是镜像的,在垂直方向上是翻转的

1 个答案:

答案 0 :(得分:9)

原因和快速修复:

问题出在这部分:

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