WPF程序使用GDI设备字体(如ZEBRA字体)的实现方案咨询
Font.FromLogFont是GDI+的封装方法,本身仅支持系统已注册的TrueType/OpenType字体。ZEBRA这类打印机的内置设备字体不会安装到系统全局字体目录,属于绑定在对应打印机设备上下文(HDC)上的专有资源,GDI+和WPF原生的DirectWrite字体子系统都无法直接将其识别为可复用的字体对象,调用转换时必然抛出异常:
Only truetype fonts are supported. This is not a TrueType Font
方案1:GDI原生渲染转WPF位图(推荐,效果与打印输出完全一致)
既然已经完成了GDI层的LOGFONT枚举、拿到了对应打印机的HDC,完全可以跳过System.Drawing.Font的转换逻辑,直接用GDI原生接口渲染文本,再把渲染结果转成WPF支持的位图格式显示:
实现步骤:
- 基于打印机HDC调用
CreateCompatibleDC创建内存兼容设备上下文 - 调用
CreateFontIndirect传入已存储的目标LOGFONT结构体,得到GDI字体句柄HFONT,通过SelectObject将字体选入刚创建的内存兼容DC - 根据待渲染文本的尺寸创建对应大小的兼容位图,选入内存DC
- 调用
ExtTextOut或TextOutGDI函数,将目标文本绘制到内存DC绑定的位图上 - 调用WPF互操作接口
System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap,将GDI生成的HBITMAP转为BitmapSource,直接赋值给WPF的Image控件即可显示 - 所有GDI创建的资源(HFONT、HBITMAP、兼容HDC)用完后,必须调用
DeleteObject、DeleteDC手动释放,避免GDI对象泄漏导致程序崩溃。
这个方案的渲染逻辑和打印机实际输出时的字体渲染逻辑完全同源,不会出现字形、字宽匹配偏差,最适合需要打印预览的场景。
方案2:参数映射做近似预览
如果不需要完全还原打印效果,只需要做排版位置参考,可以直接从已存储的LOGFONT结构体里提取lfFaceName、lfWeight、lfHeight、lfItalic等参数,映射为WPF原生的Typeface、FormattedText对象:优先查找系统内同名字体,找不到就用字宽、字重接近的系统字体兜底显示。
注意:绝大多数打印机内置设备字体不会在系统中注册可安装版本,这个方案只能做粗略的排版参考,无法还原设备字体的实际字形。
不要尝试把非TrueType的设备字体强制转换为System.Drawing.Font或者WPFTypeface,这两套字体子系统从底层就没有提供对打印机设备字体的兼容支持,在转换逻辑上调试没有意义。
内容的提问来源于stack exchange,提问作者frankborty

