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

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#内部渲染页面的方案不合理

问题分析与解决

核心问题原因

  1. HTML转换未强制字体嵌入:给FontProvider添加了自定义字体,但HtmlConverter转换时未强制嵌入字体逻辑,PDF/A-3要求所有字体必须嵌入,一旦触发未嵌入字体的使用就会报错。
  2. 元素字体优先级冲突:给Cell设置的自定义字体,被HTML转换生成元素自带的字体设置覆盖,导致未嵌入字体被调用。
  3. 标准字体的隐患:调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:50:27