使用Svg.Skia转换SVG到PDF时自定义字体不生效问题
你的代码中FromFamilyName方法已被触发并返回字体,但PDF中未生效,可能是字体匹配逻辑、字体元数据匹配或加载方式的问题,以下是具体排查和解决方法:
1. 确认加载字体的实际元数据
首先要明确你加载的OTF字体实际的FamilyName、Weight等参数,因为字体文件内部的元数据可能和你预期的不一致(比如你以为家族名是"Font",实际可能是"Font Bold")。修改你的AddTypeface方法,添加日志输出:
public void AddTypeface(Stream stream) { var typeface = _fontManager.CreateTypeface(stream); if (typeface == null) { // 字体加载失败,需检查资源流是否正确 return; } // 打印字体元数据,确认实际值 Console.WriteLine($"加载字体:FamilyName={typeface.FamilyName}, Weight={typeface.FontStyle.Weight}, Slant={typeface.FontStyle.Slant}"); _typefaces.Add(typeface); }
运行后查看输出,对比SVG中font-family、font-weight的值是否和字体实际元数据匹配。比如如果输出的FamilyName是"Font Bold",那么SVG中的font-family应该改为"Font Bold",或者调整匹配逻辑。
2. 优化字体匹配逻辑
你当前的匹配逻辑是严格等于所有参数,这很容易因为字体实际参数和SVG中的设置不完全一致而失败(比如有些粗体字体的Weight是800而非标准的700)。修改FromFamilyName方法,采用更宽松的匹配策略:
public SKTypeface? FromFamilyName(string fontFamily, SKFontStyleWeight fontWeight, SKFontStyleWidth fontWidth, SKFontStyleSlant fontStyle) { // 先匹配家族名(忽略大小写) var candidates = _typefaces .Where(t => string.Equals(t.FamilyName, fontFamily, StringComparison.OrdinalIgnoreCase)) .ToList(); if (!candidates.Any()) return null; // 过滤倾斜样式匹配的 candidates = candidates.Where(t => t.FontStyle.Slant == fontStyle).ToList(); if (!candidates.Any()) return null; // 选择权重最接近的字体,而非严格等于 return candidates.OrderBy(t => Math.Abs((int)fontWeight - t.FontStyle.Weight)).FirstOrDefault(); }
这种方式会优先匹配家族名和倾斜样式,再选择与目标权重最接近的字体,大幅提升命中概率。
3. 尝试直接注册字体到默认字体管理器
自定义ITypefaceProvider并非必须,你可以直接将字体注册到SkiaSharp的默认字体管理器,让系统自动处理字体查找:
var fontResources = new[] { "SomeNamespace.fonts.Fonts.Font Bold.otf" }; foreach (var fontResource in fontResources) { using var fontStream = typeof(ThisClass).Assembly.GetManifestResourceStream(fontResource)!; // 将字体注册到默认字体管理器 if (!SKFontManager.Default.Register(fontStream)) { // 注册失败处理 } } var svg = new SKSvg(); // 无需设置TypefaceProviders,默认会从系统和注册的字体中查找 svg.FromSvg(svgContent); var picture = svg.Picture!; var memoryStream = new MemoryStream(); picture.ToPdf(memoryStream, SKColors.Transparent, 1f, 1f); return memoryStream;
这种方式更简洁,且能避免自定义Provider可能出现的匹配问题。
4. 检查PDF字体嵌入情况
如果以上步骤都无效,可能是PDF未嵌入字体导致查看器使用替代字体。你可以通过SKDocument手动生成PDF,确保字体嵌入:
using var document = SKDocument.CreatePdf(memoryStream); using var canvas = document.BeginPage(picture.CullRect.Width, picture.CullRect.Height); canvas.DrawPicture(picture); document.EndPage(); document.Close();
这种方式更底层,能确保SkiaSharp正确处理字体嵌入。
内容的提问来源于stack exchange,提问作者kthuis

