C# iText7给PDF/A-3添加HTML水印时字体未嵌入报错排查
问题:iText7给PDF/A-3添加HTML水印时字体未嵌入报错
作为C#新手,使用iText7给PDF/A-3添加HTML水印时遇到报错:All the fonts must be embedded. This one is not: {0},尽管已尝试在各处嵌入字体。相关代码如下:
... var font = PdfFontFactory.CreateFont("assets/fonts/default.ttf", PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED); // always not null font.SetSubset(false); doc.AddFont(font); var fs = new iText.Layout.Font.FontProvider(); fs.AddFont("assets/fonts/default.ttf"); fs.AddStandardPdfFonts(); var elements = HtmlConverter.ConvertToElements(new MemoryStream(watermark.Content), new ConverterProperties().SetFontProvider(fs)); Table table = new Table(UnitValue.CreatePercentArray(new float[] { 4, 1, 3 })).UseAllAvailableWidth(); // subject to change, taken from official docs var cell = new Cell(); cell.SetFont(font).Add((IBlockElement)elements[0]); table.AddCell(cell); var page = doc!.GetFirstPage(); // always not null PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), doc.Document); new Canvas(canvas, page.GetPageSize()).Add(cell) .Close(); return doc;
补充说明:
- 需将HTML作为水印添加到PDF/A-3首页,仅需实现类似图片盖印的效果,无需关注HTML标签、字体细节
- 无法控制传入的HTML,无法手动设置字体,不确定会收到哪些字体,希望HtmlConverter支持全局预设字体但暂不可行
- 目前采用HTML转元素+表格+Canvas的方案,考虑过转PNG但C#内部渲染页面的方案不合理
问题分析与解决
核心问题原因
- HTML转换未强制字体嵌入:给
FontProvider添加了自定义字体,但HtmlConverter转换时未强制嵌入字体逻辑,PDF/A-3要求所有字体必须嵌入,一旦触发未嵌入字体的使用就会报错。 - 元素字体优先级冲突:给
Cell设置的自定义字体,被HTML转换生成元素自带的字体设置覆盖,导致未嵌入字体被调用。 - 标准字体的隐患:调用
fs.AddStandardPdfFonts()引入的标准PDF字体(如Helvetica)默认不嵌入,若HTML隐式使用这类默认字体,直接违反PDF/A-3规范。
可行解决办法
方案1:强制嵌入+禁用标准字体
- 移除
fs.AddStandardPdfFonts(),避免未嵌入的标准字体被使用 - 给
ConverterProperties开启强制字体嵌入,并设置自定义字体为默认 fallback:
var fs = new iText.Layout.Font.FontProvider(); fs.AddFont("assets/fonts/default.ttf"); // 设置自定义字体为默认字体 fs.SetDefaultFont(PdfFontFactory.CreateFont("assets/fonts/default.ttf").GetFontProgram().GetFontNames().GetFontName()); var converterProps = new ConverterProperties() .SetFontProvider(fs) .SetFontEmbedding(true); // 强制嵌入所有转换用到的字体 var elements = HtmlConverter.ConvertToElements(new MemoryStream(watermark.Content), converterProps);
方案2:将HTML转为Form XObject统一处理
把HTML转换为独立的PdfFormXObject,确保转换过程中所有字体都被嵌入,再添加到目标PDF的Canvas:
// 先将HTML转换为Form XObject var fs = new iText.Layout.Font.FontProvider(); fs.AddFont("assets/fonts/default.ttf"); var converterProps = new ConverterProperties() .SetFontProvider(fs) .SetFontEmbedding(true); var tempPdf = new PdfDocument(new PdfWriter(new MemoryStream())); var tempDoc = new Document(tempPdf); var elements = HtmlConverter.ConvertToElements(new MemoryStream(watermark.Content), converterProps); foreach (var elem in elements) { if (elem is IBlockElement block) { tempDoc.Add(block); } } tempDoc.Close(); // 提取XObject并添加到目标页面 var pageXobj = tempPdf.GetFirstPage().CopyAsFormXObject(doc.Document); var page = doc.GetFirstPage(); PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), doc.Document); canvas.AddXObject(pageXobj, 0, 0); // 可调整参数控制水印位置
方案3:强制替换所有HTML字体为自定义嵌入字体
通过FontProvider的字体范围映射,把所有字符都绑定到自定义嵌入字体,彻底避免未知字体的使用:
var customFontProgram = FontProgramFactory.CreateFont("assets/fonts/default.ttf"); var fs = new iText.Layout.Font.FontProvider(); fs.AddFont(customFontProgram, PdfEncodings.WINANSI); // 把所有字符范围都映射到自定义字体 fs.AddFontRange(new Range(0, char.MaxValue), customFontProgram); var converterProps = new ConverterProperties() .SetFontProvider(fs) .SetFontEmbedding(true); var elements = HtmlConverter.ConvertToElements(new MemoryStream(watermark.Content), converterProps);
内容的提问来源于stack exchange,提问作者GettingPleasure
相关产品推荐
相关产品推荐

