PDF 生成模板编辑器
开源可视化 PDF 生成引擎,支持自定义模板,并提供面向开发者的 API,灵活构建文档生成流程。
通过 CPDFDocument 的 validateStandardPDFWithType:basePath:,可以按指定标准对已打开的文档执行基础规则检查,并返回 CPDFStandardValidationResult。验证针对的是内存中已打开的文档,如需验证转换结果,请先打开转换输出的文件再进行验证。
支持的验证目标
| 标准 | format | typenum | partType | 状态 |
|---|---|---|---|---|
| PDF/A-1a、1b | CPDFStandardFormatPDFA | 1 | CPDFPartTypePDF_a、CPDFPartTypePDF_b | 正式 |
| PDF/A-2a、2u、2b、PDF/A-3a、3u、3b | CPDFStandardFormatPDFA | 2、3 | CPDFPartTypePDF_a、CPDFPartTypePDF_u、CPDFPartTypePDF_b | 正式 |
| PDF/E-1、E-2 | CPDFStandardFormatPDFE | 1、2 | CPDFPartTypeNone | 正式 |
| PDF/X-1a、X-3、X-4 | CPDFStandardFormatPDFX | 1、3、4 | CPDFPartTypeNone | 实验性 |
| PDF/UA | CPDFStandardFormatPDFUA | 忽略 | CPDFPartTypeNone | 实验性 |
| PDF/VT | CPDFStandardFormatPDFVT | 忽略(按文档声明的 VT 级别检查) | CPDFPartTypeNone | 实验性 |
basePath 是用于解析外部引用文件的目录,仅在验证 PDF/X 时使用,可以传 nil。
出现以下情况时,该方法返回 nil:
验证结果
CPDFStandardValidationResult 的属性:
| 属性 | 类型 | 说明 |
|---|---|---|
passed | BOOL | 文档是否符合所验证的标准。 |
detectedType | CPDFStandardMode | 文档声明的标准级别;验证 PDF/E、PDF/UA、PDF/VT 时为 nil。 |
issues | NSArray<CPDFStandardValidationIssue *> | 检查出的问题列表。 |
CPDFStandardValidationIssue 的属性:
| 属性 | 类型 | 说明 |
|---|---|---|
code | NSInteger | 核心库给出的问题编号。 |
ruleId | NSString | 违反的规则标识,例如标准中的条款,可能为空。 |
message | NSString | 问题描述。 |
pageIndex | NSInteger | 问题所在页面的索引;为 -1 时表示文档级问题。 |
standardName | NSString | 规则所属的标准名称,可能为空。 |
severity | CPDFStandardValidationSeverity | 问题的严重程度。 |
CPDFStandardValidationSeverity 的取值:
| 取值 | 说明 |
|---|---|
CPDFStandardValidationSeverityError | 错误,导致文档不符合标准。 |
CPDFStandardValidationSeverityWarning | 警告。 |
CPDFStandardValidationSeverityInfo | 信息性提示。 |
“已转换”与“已通过验证”
转换方法返回成功,只表示已生成目标标准的文档(已转换);文档是否符合标准规则,需要再调用验证方法确认(passed 为 YES 表示已通过基础验证)。这是两个不同的状态,建议在界面中分别展示。
以下是将文档转换为 PDF/A-2b 后,验证转换结果并输出问题列表的示例代码:
let document = CPDFDocument(url: URL(fileURLWithPath: pdfPath))
let pdfA2b = CPDFStandardMode()
pdfA2b.format = .PDFA
pdfA2b.typenum = 2
pdfA2b.partType = .pdf_b
do {
// 1. 转换为 PDF/A-2b
try document?.writeStandardPDF(toFilePath: savePath, withType: pdfA2b, iccFilePath: nil, with: nil, isSaveFontSubset: false, error: ())
} catch {
print("Conversion failed: \((error as NSError).localizedFailureReason ?? "")")
return
}
// 2. 打开转换结果并按 PDF/A-2b 验证
let convertedDocument = CPDFDocument(url: URL(fileURLWithPath: savePath))
guard let result = convertedDocument?.validateStandardPDF(withType: pdfA2b, basePath: nil) else {
// 文档未加载、目标标准不支持或许可证不包含 PDF/A 转换权限
return
}
print("Passed: \(result.passed)")
for issue in result.issues {
let level: String
switch issue.severity {
case .error:
level = "Error"
case .warning:
level = "Warning"
default:
level = "Info"
}
// pageIndex 为 -1 表示文档级问题
let location = issue.pageIndex == -1 ? "Document" : "Page \(issue.pageIndex + 1)"
print("[\(level)] \(location) \(issue.ruleId): \(issue.message)")
}CPDFDocument *document = [[CPDFDocument alloc] initWithURL:[NSURL fileURLWithPath:pdfPath]];
CPDFStandardMode *pdfA2b = [[CPDFStandardMode alloc] init];
pdfA2b.format = CPDFStandardFormatPDFA;
pdfA2b.typenum = 2;
pdfA2b.partType = CPDFPartTypePDF_b;
// 1. 转换为 PDF/A-2b
NSError *error = nil;
if (![document writeStandardPDFToFilePath:savePath
withType:pdfA2b
iccFilePath:nil
withUAConfig:nil
isSaveFontSubset:NO
error:&error]) {
NSLog(@"Conversion failed: %@", error.localizedFailureReason);
return;
}
// 2. 打开转换结果并按 PDF/A-2b 验证
CPDFDocument *convertedDocument = [[CPDFDocument alloc] initWithURL:[NSURL fileURLWithPath:savePath]];
CPDFStandardValidationResult *result = [convertedDocument validateStandardPDFWithType:pdfA2b basePath:nil];
if (!result) {
// 文档未加载、目标标准不支持或许可证不包含 PDF/A 转换权限
return;
}
NSLog(@"Passed: %d", result.passed);
for (CPDFStandardValidationIssue *issue in result.issues) {
NSString *level = @"Info";
if (issue.severity == CPDFStandardValidationSeverityError) {
level = @"Error";
} else if (issue.severity == CPDFStandardValidationSeverityWarning) {
level = @"Warning";
}
// pageIndex 为 -1 表示文档级问题
NSString *location = issue.pageIndex == -1 ? @"Document" : [NSString stringWithFormat:@"Page %ld", (long)issue.pageIndex + 1];
NSLog(@"[%@] %@ %@: %@", level, location, issue.ruleId, issue.message);
}注: 标准验证为基础规则检查,不等同于第三方专业校验器的完整合规认证。PDF/X、PDF/UA 和 PDF/VT 验证为实验性功能,结果可能不完整。