FontCollection.LoadFonts 无法加载 .ttf 文件,主因是路径错误、流未重置位置或资源名不匹配;需确保 stream 可读且 position=0,嵌入资源用 GetManifestResourceNames 验证全名,加载后调用 GetFont 测试解析,并在 TextGraphicsOptions 中显式注入 FontDescription。

FontCollection.LoadFonts 无法加载 .ttf 文件?检查路径和流释放
直接用 FontCollection.LoadFonts("font.ttf") 报错“file not found”或空字体列表,大概率是路径没解析对,或者文件被其他进程占用。ImageSharp 本身不负责字体加载,SixLabors.Fonts 才是核心——它要求传入的 Stream 必须可读、未关闭、且位置在开头。
常见错误:用 File.OpenRead() 后没重置位置;或用 Assembly.GetExecutingAssembly().GetManifestResourceStream() 加载嵌入资源时路径写错(注意命名空间前缀)。
- 本地文件推荐用
new FileStream(path, FileMode.Open, Fileaccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous),确保可异步读取且不被锁死 - 嵌入资源务必确认完整资源名,可用
Assembly.GetExecutingAssembly().GetManifestResourceNames()调试输出验证 - 加载后建议立刻调用
fontCollection.GetFont("FontName", 400, FontStyle.Regular)测试是否真能解析出字体族,避免“静默失败”
ImageSharp 绘制文字时提示 “No fonts registered”
这说明 FontCollection 实例没传给 TextGraphicsOptions,或传了但没生效。ImageSharp 2.x+ 不再全局注册字体,必须显式绑定到绘图上下文。
关键点在于:不是把 FontCollection 存起来就行,而是在每次创建 TextGraphicsOptions 时通过 FontCollection 构造参数注入:
var options = new TextGraphicsOptions(true) { Font = fontCollection.CreateFont("Noto Sans CJK SC", 16), // 注意:这里 Font 是 FontDescription 类型,不是 FontFamily 或 string };
如果字体名含空格或中英文混排(如 “microsoft YaHei”),务必用实际 PostScript 名(可用 FontForge 或 font.FamilyName 输出确认),别依赖显示名。
中文乱码或方块字?优先检查字体是否支持 Unicode 区段
SixLabors.Fonts 默认只加载基本 ASCII 字形,遇到中文会 fallback 到缺失字形(□)。即使加载了 NotoSansCJK.ttc,也得确认你调用的是支持 CJK 的子字体(如 "Noto Sans CJK SC",不是 "Noto Sans")。
- 用
fontCollection.Families遍历所有已加载家族,打印family.Name和family.GetRegularFont().Glyphs.count,看是否有足够多字形(中文字体通常 >20000) - 避免用
CreateFont("SimSun", size)—— windows 系统字体名在 linux/macOS 上不存在,跨平台必须带字体文件 - 绘制中文前加一句
options.VerticalAlignment = VerticalAlignment.Top;,防止 baseline 偏移导致截断
性能敏感场景下避免重复加载字体文件
每次 LoadFonts 都会解析整个 TTF/OTF 表结构,开销不小。字体文件应作为单例复用,而不是每次绘图都新建 FontCollection。
典型安全做法是静态初始化:
public static class FontProvider { public static readonly FontCollection Collection = new(); static FontProvider() { using var stream = typeof(FontProvider).Assembly.GetManifestResourceStream("Assets.NotoSansCJKsc-Regular.otf"); Collection.LoadFonts(stream); } }
注意:不要在静态构造器里用 await,SixLabors.Fonts 的 LoadFonts 没有异步重载;若字体来自网络或慢存储,需提前预热并缓存 Font 实例,而非反复查 GetFont。
最易忽略的一点:FontCollection 不是线程安全的,但它的 GetFont 方法是——只要不同时调用 LoadFonts,多个线程共用同一个实例没问题。