在 Delphi 10.3 Firemonkey 中将 TPaintBox Canvas 的内容保存到位图(and/or 文件)

Saving content of TPaintBox Canvas to a Bitmap (and/or a file) in Delphi 10.3 Firemonkey

Delphi Android 的 10.3.3 Firemonkey 应用程序。 我在 OnPaint 事件的 TPaintBox Canvas 中绘制了很多对象。 现在我需要将 PaintBox.Canvas 的全部内容保存在 a Bitmap 中,最后保存在文件 中。 如何做到这一点? 阅读 RAD 文档,在互联网上搜索 - 找不到解决方案。

更新1:

根据@MBo、@Remy-Lebeau、@Adam-Henderson 的评论我试过了,但只有 50% 的成功率...

我创造了

procedure GameCanvasPaint(Canvas: TCanvas);

在我调用的 PaintBox OnPaint 事件中,绘制成功:

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  GameCanvasPaint( Canvas );
end;

现在我想创建位图并共享它,同时调用相同的绘图函数:

procedure TForm1.ShowShareSheetAction1BeforeExecute(Sender: TObject);
begin
// g_bmp_share is TBitmap already created earlier
  g_bmp_share.SetSize( Paintbox1.Canvas.Width, Paintbox1.Canvas.Height );
  g_bmp_share.Canvas.Clear($FFFFFF);
  GameCanvasPaint( g_bmp_share.Canvas );
  ShowShareSheetAction1.Bitmap.Assign( g_bmp_share );
end;

结果: 共享图片黑色...上面什么都没有,只有黑色谁能告诉我为什么?

将您的绘图代码移动到一个以 TCanvas 作为输入的可重用函数中,然后您可以让 OnPaint 处理程序使用 TPaintBox canvas 调用该函数,并且您的保存代码使用 TBitmap canvas.

调用该函数

注意在FMXTBitmapcanvas上绘制时需要先调用Canvas.BeginScene():

Notifies the TCanvas object that the drawing can begin.

Call BeginScene before drawing on the TCanvas.

To end the drawing session, call EndScene.

procedure TForm1.GameCanvasPaint(Canvas: TCanvas);
begin
  //...
end;

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  GameCanvasPaint( Canvas );
end;

procedure TForm1.ShowShareSheetAction1BeforeExecute(Sender: TObject);
begin
  // g_bmp_share is TBitmap already created earlier
  g_bmp_share.SetSize( Paintbox1.Width, Paintbox1.Height );
  if g_bmp_share.Canvas.BeginScene then
  try
    g_bmp_share.Canvas.Clear($FFFFFF);
    GameCanvasPaint( g_bmp_share.Canvas );
  finally
    g_bmp_share.Canvas.EndScene;
  end;
  ShowShareSheetAction1.Bitmap.Assign( g_bmp_share );
end;

您不需要在 OnPaint 事件中执行此操作,因为 FMX 在触发事件之前会为您调用 BeginScene()

Tip: Notice that calling BeginScene in the OnPaint event handlers has no effect, because BeginScene is called before the OnPaint event handler runs. This guarantees that painting always occurs in OnPaint without requiring extra and probably unexpected code to allow drawing to have an effect.