PDF/A是ISO 19005定义的归档标准,要求字体嵌入、禁加密、禁JS、明确定义颜色空间和元数据;C#默认生成的PDF不满足这些强制约束,需用iText7.4.0+显式配置PDF/A合规性。
PDF/A 是什么,为什么 C# 默认生成的 PDF 不是 PDF/A
PDF/A 不是“带 A 的 PDF”,而是 ISO 标准(ISO 19005)定义的一类严格归档格式:所有字体必须嵌入、禁止加密、禁用 JavaScript、颜色空间需明确指定、元数据必须完整。C# 原生
或常见库如
(旧版)、
默认输出的是普通 PDF,连字体嵌入都未必触发——更别说校验 PDF/A 合规性了。
关键点在于:生成 ≠ 合规。你调用
写入文字,若字体未显式嵌入且子集化,或未写入
元数据块,工具(如 veraPDF)一扫就报
或
。
用 iText7 创建 PDF/A-1b 或 PDF/A-2u 的最小必要步骤
iText7 是目前 C# 生态中对 PDF/A 支持最稳的库(注意:必须用
,旧版 iTextSharp 不支持 PDF/A)。它不靠“开关”启用 PDF/A,而靠构造特定
和
实例,并全程遵守约束链。
必须使用
构造时传入
(或
)
文档创建后立即调用
(PDF/A-1b 要求逻辑结构标签)
所有字体必须用
显式加载并设为嵌入(第三个参数
)
必须设置输出意图(OutputIntent):用
配置项,否则 veraPDF 报
必须写入 XMP 元数据:调用
+
,再手动注入 XMP 字符串(iText7 不自动补全)
示例关键片段:
常见失败现象和对应检查点
用 veraPDF 或 PDF/A 验证器扫出失败,别急着改代码——先看错误类型,再定位环节:
C知道
CSDN推出的一款AI技术问答工具
下载
:不是“用了系统字体”,而是没在
中传
;或用了
(iText7 已弃用,会静默失败)
:OutputIntent 字典字段名拼错(比如写成
而非
),或 profile 流未正确绑定
:没调用
,或没手动注入 XMP(iText7 不自动生成,需用
补)
:字体文件路径无效(如相对路径在服务端找不到),或字体本身不支持 Unicode 子集(某些 .ttf 有 license 限制)
验证必须用 veraPDF(开源)或 callas
pdf
Toolbox(商业),Windows 自带的“打印为 PDF”或 Adobe Acrobat “另存为 PDF/A” 按钮生成的文件,常绕过底层校验,不可信。
PDF/A-1b vs PDF/A-2u:选哪个,差别在哪
PDF/A-1b(ISO 19005-1)只保证视觉可再现,不支持透明度、图层、JPEG2000;PDF/A-2u(ISO 19005-2)允许 JPEG2000、OpenType 字体、数字签名,且支持 Unicode 文本搜索(
即 Unicode)。但代价是:PDF/A-2u 对字体嵌入要求更严(必须含 Unicode cmap),且部分老旧归档系统只认 PDF/A-1b。
如果目标系统明确要求“PDF/A-1b”,别用
—— veraPDF 会直接判失败,不给提示
PDF/A-2u 必须用
+ 真实 Unicode 字体(如 Noto Sans CJK),用
会因缺少 cmap 报
两者都不支持
表单字段的交互行为,但 PDF/A-2u 允许表单域存在(只读),PDF/A-1b 连域对象都禁止
归档场景下,除非你确定下游系统支持 PDF/A-2u 且需要 Unicode 搜索,否则优先选 PDF/A-1b——兼容性陷阱少,验证通过率高。
字体嵌入、OutputIntent 字典、XMP 元数据这三处,漏一个,veraPDF 就红标。没有“差不多合规”,只有“全绿才过关”。
System.Drawing.PrintingiTextSharpPdfSharpdocument.Add()XMPMissingEmbeddedFontInvalidOutputIntentiText7.4.0+PdfWriterPdfDocumentPdfWriternew WriterProperties().SetPdfVersion(PdfVersion.PDF_1_7).SetPdfAConformance(PdfAConformance.PDF_A_1B)PDF_A_2UpdfDoc.SetTagged()PdfFontFactory.CreateFont(..., PdfEncodings.IDENTITY_H, true)truesRGB IEC61966-2.1MissingOutputIntentpdfDoc.GetCatalog().SetLang("en-US")pdfDoc.GetCatalog().SetViewerPreferences(...)PdfWriter writer = new PdfWriter("out.pdf",
new WriterProperties().SetPdfVersion(PdfVersion.PDF_1_7)
.SetPdfAConformance(PdfAConformance.PDF_A_1B));
PdfDocument pdfDoc = new PdfDocument(writer);
pdfDoc.SetTagged();
// 加载字体(必须!)
PdfFont font = PdfFontFactory.CreateFont(StandardFonts.HELVETICA,
PdfEncodings.IDENTITY_H, true);
// 设置 OutputIntent(硬编码路径,不可省)
ColorSpace cs = new IccBased(new PdfName("sRGB IEC61966-2.1"));
pdfDoc.GetCatalog().Put(new PdfName("OutputIntents"),
new PdfArray().Add(new PdfDictionary()
.Put(new PdfName("S"), new PdfName("GTS_PDFA1"))
.Put(new PdfName("OutputCondition"), new PdfString("sRGB IEC61966-2.1"))
.Put(new PdfName("OutputConditionIdentifier"), new PdfString("sRGB IEC61966-2.1"))
.Put(new PdfName("Info"), new PdfString("sRGB IEC61966-2.1"))
.Put(new PdfName("DestOutputProfile"), new PdfStream(cs.GetProfile()))));
MissingEmbeddedFontPdfFontFactory.CreateFont()trueBaseFont.CreateFont()InvalidOutputIntent"OutputConditionID""OutputConditionIdentifier"MissingXMPMetadatapdfDoc.GetCatalog().SetLang()pdfDoc.GetCatalog().Put(new PdfName("Metadata"), metadataStream)NonEmbeddedFontuPdfAConformance.PDF_A_2UPdfEncodings.IDENTITY_HStandardFonts.HELVETICAInvalidUnicodeMappingAcroForm