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
相关产品推荐
相关产品推荐

