Delphi打印Canvas报EConvertError:无法将TCanvasD2D分配给TCanvasGdiPlus
问题描述
程序中使用Canvas绘制消费购物小票,完成绘制后尝试打印该Canvas内容时程序抛出异常,具体报错信息如下:
Project Project2.exe raised exception class EConvertError with message 'Cannot assign a TCanvasD2D to a TCanvasGdiPlus'
对应出错的实现代码:
var printDialog : TPrintDialog; myPrinter : TPrinter; begin printDialog := TPrintDialog.Create(Form5); if printDialog.Execute then begin myPrinter := printer; with myPrinter do begin BeginDoc; Canvas.Assign(slipPnl.Canvas); EndDoc; end; end; end;
报错原因
触发这个错误的核心原因是Canvas.Assign()方法仅支持同类型底层渲染实现的Canvas对象互相赋值:
- 小票所在控件
slipPnl的Canvas是Direct2D渲染实现的TCanvasD2D类型 - 打印机对象的Canvas是GDI+渲染实现的
TCanvasGdiPlus类型
两种Canvas底层渲染逻辑完全不同,不存在直接赋值转换的可能,因此抛出类型转换错误。
修复方案
- 放弃直接跨Canvas类型调用
Assign拷贝内容的写法,用临时位图作为中转载体:先把控件上绘制的小票内容绘制到临时位图,再把位图绘制到打印机画布上完成打印。 - 涉及打印操作时要手动加异常兜底,打印过程出错时及时调用
Abort终止打印任务,避免打印机残留异常挂起的任务。 - 对打印清晰度有要求的场景,可以按照打印机实际DPI换算位图尺寸,不要直接用屏幕分辨率的位图拉伸打印,避免输出模糊。
修复后的参考实现代码:
var printDialog : TPrintDialog; myPrinter : TPrinter; tempBmp : TBitmap; begin printDialog := TPrintDialog.Create(Form5); try if printDialog.Execute then begin myPrinter := Printer; tempBmp := TBitmap.Create; try // 把控件画布上的小票内容拷贝到临时位图 tempBmp.Width := slipPnl.Width; tempBmp.Height := slipPnl.Height; tempBmp.Canvas.CopyRect( Rect(0, 0, tempBmp.Width, tempBmp.Height), slipPnl.Canvas, Rect(0, 0, slipPnl.Width, slipPnl.Height) ); myPrinter.BeginDoc; try // 按打印页尺寸把小票位图绘制到打印机画布 myPrinter.Canvas.StretchDraw( Rect(0, 0, myPrinter.PageWidth, myPrinter.PageHeight), tempBmp ); myPrinter.EndDoc; except myPrinter.Abort; raise; end; finally tempBmp.Free; end; end; finally printDialog.Free; end; end;
内容的提问来源于stack exchange,提问作者Bradley Rice
相关产品推荐
相关产品推荐

