您的 PDF 中的问题非常类似于上一节“父树条目的另一个问题”中讨论的问题,该问题“从选择中查找标签”在标记的 pdf 中不起作用?通过迷人的编码器:
在您的父树中,您没有引用 MCID 的实际父结构元素,但您引用了一个新的结构树节点,该节点声称将结构层次结构中的实际父节点作为其自己的父节点(实际上不是其子节点之一)和还声称小时候有问题的 MCID。
相反,您应该简单地引用 MCID 的实际父结构元素。
正如您的问题标题询问如何在由 pdfBox 创建的 PDF 中修复不一致的父树映射时,这里是一种通过从结构树中重建父树来修复父树的方法。
首先按页面递归收集 MCID 及其父结构树元素,例如使用如下方法:
void collect(PDPage page, PDStructureNode node, Map<PDPage, Map<Integer, PDStructureNode>> parentsByPage) {
COSDictionary pageDictionary = node.getCOSObject().getCOSDictionary(COSName.PG);
if (pageDictionary != null) {
page = new PDPage(pageDictionary);
}
for (Object object : node.getKids()) {
if (object instanceof COSArray) {
for (COSBase base : (COSArray) object) {
if (base instanceof COSDictionary) {
collect(page, PDStructureNode.create((COSDictionary) base), parentsByPage);
} else if (base instanceof COSNumber) {
setParent(page, node, ((COSNumber)base).intValue(), parentsByPage);
} else {
System.out.printf("?%s\n", base);
}
}
} else if (object instanceof PDStructureNode) {
collect(page, (PDStructureNode) object, parentsByPage);
} else if (object instanceof Integer) {
setParent(page, node, (Integer)object, parentsByPage);
} else {
System.out.printf("?%s\n", object);
}
}
}
( RebuildParentTreeFromStructure方法)
使用这个辅助方法
void setParent(PDPage page, PDStructureNode node, int mcid, Map<PDPage, Map<Integer, PDStructureNode>> parentsByPage) {
if (node == null) {
System.err.printf("Cannot set null as parent of MCID %s.\n", mcid);
} else if (page == null) {
System.err.printf("Cannot set parent of MCID %s for null page.\n", mcid);
} else {
Map<Integer, PDStructureNode> parents = parentsByPage.get(page);
if (parents == null) {
parents = new HashMap<>();
parentsByPage.put(page, parents);
}
if (parents.containsKey(mcid)) {
System.err.printf("MCID %s already has a parent. New parent rejected.\n", mcid);
} else {
parents.put(mcid, node);
}
}
}
(RebuildParentTreeFromStructure辅助方法)
然后根据收集到的信息进行重建:
void rebuildParentTreeFromData(PDStructureTreeRoot root, Map<PDPage, Map<Integer, PDStructureNode>> parentsByPage) {
int parentTreeMaxkey = -1;
Map<Integer, COSArray> numbers = new HashMap<>();
for (Map.Entry<PDPage, Map<Integer, PDStructureNode>> entry : parentsByPage.entrySet()) {
int parentsId = entry.getKey().getCOSObject().getInt(COSName.STRUCT_PARENTS);
if (parentsId < 0) {
System.err.printf("Page without StructsParents. Ignoring %s MCIDs.\n", entry.getValue().size());
} else {
if (parentTreeMaxkey < parentsId)
parentTreeMaxkey = parentsId;
COSArray array = new COSArray();
for (Map.Entry<Integer, PDStructureNode> subEntry : entry.getValue().entrySet()) {
array.growToSize(subEntry.getKey() + 1);
array.set(subEntry.getKey(), subEntry.getValue());
}
numbers.put(parentsId, array);
}
}
PDNumberTreeNode numberTreeNode = new PDNumberTreeNode(PDParentTreeValue.class);
numberTreeNode.setNumbers(numbers);
root.setParentTree(numberTreeNode);
root.setParentTreeNextKey(parentTreeMaxkey + 1);
}
( RebuildParentTreeFromStructure方法)
像这样应用
PDDocument document = PDDocument.load(SOURCE));
rebuildParentTree(document);
document.save(RESULT);
(RebuildParentTreeFromStructure测试testTestdatei
)
PAC3 和 Adobe Preflight(至少在我的旧 Acrobat 9.5 中)全部变为绿色,结果如下:
注意:这还不是通用的父树重建器。它适用于手头的测试文件,具有特定类型的结构树节点和仅在页面内容流中的内容。对于通用工具,它也必须学会处理其他类型,并且还必须处理嵌入式 XObjects 中的标记内容等。