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,多个线程共用同一个实例没问题。
