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

VB.NET中PrintDocument使用PrivateFontCollection加载免安装私有字体问题

问题根因与修复方案

1. 私有字体集合(PrivateFontCollection)生命周期错误

两种方案都存在同一个核心错误:Font实例依赖加载它的PrivateFontCollection的完整生命周期,你在生成Font之后立刻释放了PrivateFontCollection,或是将PrivateFontCollection定义为方法内的局部变量,方法执行完后变量被GC回收,都会导致Font找不到对应的字体源,系统自动回退到默认字体(MS Sans Serif)。

  • 修复方案:将PrivateFontCollection定义为类级别的全局变量,在需要使用该字体的整个周期内不要释放,直到完全不需要使用该字体后再统一释放资源。

2. 内存字体资源释放顺序错误(第一种方案特有)

你注释掉Marshal.FreeCoTaskMem(FontPtr)是正确的,这块内存必须在PrivateFontCollection释放之后才能释放,不能在AddMemoryFont执行完就释放。同时你在返回Font之前调用的pfc.Families(0).Dispose()和pfc.Dispose()属于错误操作,必须删除这两行释放代码,等不需要使用字体的时候再统一释放资源。

3. 打印渲染模式配置缺失

打印默认使用GDI渲染,不支持私有内存字体,需要为打印的Graphics对象开启GDI+兼容渲染,在调用DrawString之前添加如下配置:

e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit
' WinForm应用还需要在应用启动时开启全局兼容文本渲染
Application.SetCompatibleTextRenderingDefault(True)

修复后代码示例(资源加载方案)

首先在窗体/业务类级别声明全局变量:

' 全局变量,不要放在方法内部
Private _customPfc As PrivateFontCollection
Private _openSansBold As Font

在窗体初始化或首次打印前调用一次字体加载方法:

Public Sub LoadCustomFont()
    Try
        Dim fontData As Byte() = My.Resources.OpenSans_Bold
        _customPfc = New PrivateFontCollection()
        Dim fontPtr As IntPtr = Marshal.AllocCoTaskMem(fontData.Length)
        Marshal.Copy(fontData, 0, fontPtr, fontData.Length)
        _customPfc.AddMemoryFont(fontPtr, fontData.Length)
        _openSansBold = New Font(_customPfc.Families(0), 22, FontStyle.Bold)
    Catch ex As Exception
        MsgBox("加载字体失败:" & ex.Message)
        _openSansBold = New Font(FontFamily.GenericMonospace, 8)
    End Try
End Sub

打印方法内直接使用预加载的字体:

e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit
e.Graphics.DrawString("Hello World", _openSansBold, Brushes.Black, 50, 2)

在窗体关闭/程序退出时统一释放资源:

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
        _openSansBold?.Dispose()
        If _customPfc IsNot Nothing Then
            ' 此处可将之前申请的fontPtr存为全局变量后在此处释放,应用生命周期较短的场景也可以不用手动释放,进程退出后系统会自动回收
            _customPfc.Dispose()
        End If
    End If
    MyBase.Dispose(disposing)
End Sub

本地文件加载方案修复说明

和资源加载方案逻辑一致,只需要将PrivateFontCollection改为全局变量、提前加载不要在打印方法内声明为局部变量,同时添加Graphics的TextRenderingHint配置即可正常运行。

额外校验点

如果配置完还是不生效,可以添加调试代码确认字体加载正确:

Debug.WriteLine("加载的字体名:" & _customPfc.Families(0).Name)

如果输出的字体名和预期不一致,说明资源文件嵌入错误或字体文件损坏,需要替换正确的字体文件重新嵌入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 01:06:08