You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 11 FireMonkey中TTextLayout无法在打印机画布渲染文本

问题:Delphi 11 FireMonkey中TTextLayout在打印机画布无法渲染文本

使用Delphi 11 FireMonkey框架时,直接调用TPrinter.Canvas的方法打印文本、图形、位图都正常,但用TTextLayout类做文本格式化打印时,输出结果中看不到文本内容;而在TPaintBox.Canvas或TBitmap.Canvas等常规画布上使用TTextLayout渲染则完全正常。

实际测试结果:

  • 程序界面的TPaintBox可正常显示文本与线条
  • Microsoft Print to PDF及实体打印机的输出仅显示线条,无文本
  • 通过TBitmap生成的图片文件可正常显示全部内容

测试代码如下:

uses
  FMX.TextLayout;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PaintBox1.Repaint;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DoPrint;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  DrawToFile;
end;

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

procedure TForm1.DoPrint;
begin
  if PrintDialog1.Execute then begin
    Printer.ActivePrinter.SelectDPI(1200, 1200);
    Printer.Orientation := TPrinterOrientation.poLandscape;
    Printer.BeginDoc;
    try
      if Printer.Canvas.BeginScene() then try
        DrawSomething(Printer.Canvas);
      finally
        Printer.Canvas.EndScene;
      end;
    finally
      Printer.EndDoc;
    end;
  end;
end;

procedure TForm1.DrawToFile;
var
  Bmp: TBitmap;
begin
  if SaveDialog1.Execute then begin
    Bmp := TBitmap.Create(300, 300);
    try
      Bmp.Clear(TAlphaColors.White);
      if Bmp.Canvas.BeginScene() then try
        DrawSomething(Bmp.Canvas);
      finally
        Bmp.Canvas.EndScene;
      end;
      Bmp.SaveToFile(SaveDialog1.FileName);
    finally
      Bmp.Free;
    end;
  end;
end;

procedure TForm1.DrawSomething(Canvas: TCanvas);
var
  tl: TTextLayout;
  BoldFont: TFont;
  StrokeBrush: TStrokeBrush;
begin
  tl := nil;
  BoldFont := nil;
  StrokeBrush := nil;
  try
    tl := TTextLayoutManager.DefaultTextLayout.Create();
    BoldFont := TFont.Create;
    StrokeBrush := TStrokeBrush.Create(TBrushKind.Solid, TAlphaColors.Blue);

    BoldFont.SetSettings('Arial', 96, TFontStyleExt.Create([TFontStyle.fsBold]));

    StrokeBrush.Thickness := 10.0;

    tl.BeginUpdate;
    try
      tl.TopLeft := TPointF.Create(0,0);
      tl.MaxSize := TPointF.Create(300, 300);
      tl.Text := 'Lorem'#$0A'ipsum';
      tl.WordWrap := True;
      tl.HorizontalAlign := TTextAlign.Leading;
      tl.VerticalAlign := TTextAlign.Leading;
      tl.Color := TAlphaColors.Black;
      tl.Font.SetSettings('Arial', 96, TFontStyleExt.Create([]));
      tl.Opacity := 1.0;
      tl.AddAttribute(TTextRange.Create(3, 5), TTextAttribute.Create(BoldFont, TAlphaColors.Black));
    finally
      tl.EndUpdate;
    end;
    tl.RenderLayout(Canvas);
    Canvas.DrawLine(TPointF.Create(10, 20), TPointF.Create(110, 120), 1.0, StrokeBrush);
  finally
    StrokeBrush.Free;
    BoldFont.Free;
    tl.Free;
  end;
end;

原因与解决方法

这是FireMonkey打印机画布的特性导致的问题:TTextLayout默认使用屏幕DPI计算文本布局,而打印机画布的DPI(你设置了1200DPI)远高于屏幕DPI,导致文本被绘制在打印区域之外,或者尺寸被缩放至肉眼不可见。

修正方式是让TTextLayout的DPI与当前画布的DPI保持一致,同时根据DPI调整布局的尺寸和位置:

修改后的DrawSomething方法代码:

procedure TForm1.DrawSomething(Canvas: TCanvas);
var
  tl: TTextLayout;
  BoldFont: TFont;
  StrokeBrush: TStrokeBrush;
  CanvasDPI: Single;
  ScaleFactor: Single;
begin
  tl := nil;
  BoldFont := nil;
  StrokeBrush := nil;
  try
    tl := TTextLayoutManager.DefaultTextLayout.Create();
    BoldFont := TFont.Create;
    StrokeBrush := TStrokeBrush.Create(TBrushKind.Solid, TAlphaColors.Blue);

    // 获取当前画布的DPI,匹配文本布局的DPI
    CanvasDPI := Canvas.DPI;
    tl.DPI := CanvasDPI;

    // 计算缩放因子:根据画布DPI与屏幕DPI的比例调整元素尺寸
    ScaleFactor := CanvasDPI / Screen.DPI;

    BoldFont.SetSettings('Arial', 96 * ScaleFactor, TFontStyleExt.Create([TFontStyle.fsBold]));

    StrokeBrush.Thickness := 10.0 * ScaleFactor;

    tl.BeginUpdate;
    try
      tl.TopLeft := TPointF.Create(0,0);
      // 根据缩放因子调整布局最大尺寸
      tl.MaxSize := TPointF.Create(300 * ScaleFactor, 300 * ScaleFactor);
      tl.Text := 'Lorem'#$0A'ipsum';
      tl.WordWrap := True;
      tl.HorizontalAlign := TTextAlign.Leading;
      tl.VerticalAlign := TTextAlign.Leading;
      tl.Color := TAlphaColors.Black;
      tl.Font.SetSettings('Arial', 96 * ScaleFactor, TFontStyleExt.Create([]));
      tl.Opacity := 1.0;
      tl.AddAttribute(TTextRange.Create(3, 5), TTextAttribute.Create(BoldFont, TAlphaColors.Black));
    finally
      tl.EndUpdate;
    end;
    tl.RenderLayout(Canvas);
    Canvas.DrawLine(TPointF.Create(10*ScaleFactor, 20*ScaleFactor), TPointF.Create(110*ScaleFactor, 120*ScaleFactor), 1.0*ScaleFactor, StrokeBrush);
  finally
    StrokeBrush.Free;
    BoldFont.Free;
    tl.Free;
  end;
end;

核心逻辑是让文本布局的DPI与目标画布完全匹配,同时通过缩放因子统一调整所有元素的尺寸和坐标,保证打印输出的内容和屏幕显示的效果一致。

内容的提问来源于stack exchange,提问作者T0mmiTheGreat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 06:30:43