PDFBox删除评论保持删除线

我有一个PDF,对段落有评论。 这一段很艰难。 我的要求是从特定页面删除命令。

以下代码应从我的PDF中删除特定注释,但事实并非如此。

PDDocument document = PDDocument.load(...File...); List annotations = new ArrayList(); PDPageTree allPages = document.getDocumentCatalog().getPages(); for (int i = 0; i < allPages.getCount(); i++) { PDPage page = allPages.get(i); annotations = page.getAnnotations(); List annotationToRemove = new ArrayList(); if (annotations.size() < 1) continue; else { for (PDAnnotation annotation : annotations) { if (annotation.getContents() != null && annotation.getContents().equals("Sample Strikethrough")) { annotationToRemove.add(annotation); } } annotations.removeAll(annotationToRemove); } } 

删除特定评论并在评论所适用的文本上保留删除线的最佳方法是什么?

删除特定评论并在评论所适用的文本上保留删除线的最佳方法是什么?

您实际找到的注释是子类型StrikeOut的文本标记注释,即此注释的主要外观是删除线。 因此,您不能删除此注释。 相反,您应该删除生成注释的其他外观(hover文本)的数据。

这可以这样做:

 final COSName POPUP = COSName.getPDFName("Popup"); PDDocument document = PDDocument.load(resource); List annotations = new ArrayList<>(); PDPageTree allPages = document.getDocumentCatalog().getPages(); List objectsToRemove = new ArrayList<>(); for (int i = 0; i < allPages.getCount(); i++) { PDPage page = allPages.get(i); annotations = page.getAnnotations(); for (PDAnnotation annotation : annotations) { if ("StrikeOut".equals(annotation.getSubtype())) { COSDictionary annotationDict = annotation.getCOSObject(); COSBase popup = annotationDict.getItem(POPUP); annotationDict.removeItem(POPUP); // popup annotation annotationDict.removeItem(COSName.CONTENTS); // plain text comment annotationDict.removeItem(COSName.RC); // rich text comment annotationDict.removeItem(COSName.T); // author if (popup != null) objectsToRemove.add(popup); } } annotations.removeAll(objectsToRemove); } 

( RemoveStrikeoutComment.java test testRemoveLikeStephanImproved


作为查看这个PDFBox错误的副作用变得明显:OP的原始代码应该完全删除了StrikeOut注释,但它什么也没做。 原因是在页面注释的上下文中使用COSArrayList类的错误。

page.getAnnotations()返回的页面注释列表是page.getAnnotations()一个实例。 此类带有一个COS对象列表,它们出现在页面Annots数组中,以及这些条目的包装器列表(在必要时解析间接引用之后 )。

removeAll方法(明智地)检查它的参数集合是否包含这样的包装器,并从前一个集合和参数集合中删除实际的COS对象,而不是包装器,从后者(即使用包装器)。

这适用于Annots数组中的直接对象,但是前一个列表中作为间接引用的条目未正确删除,因为代码尝试删除已解析的注释字典,而该列表实际上包含间接引用。

在手头的情况下,导致删除不被回写。 在更一般的情况下,结果甚至可能更怪异,因为现在两个列表具有不同的大小。 因此,面向索引的方法现在可以操纵列表的非对应对象......

(顺便说一句,在我上面的代码中,我删除了一个间接引用,而不是一个包装器,使列表也处于混乱状态,因为这次只删除了前者的一个条目,而不是后一个列表;这可能也应该更安全地处理。)

retainAll方法中出现类似的问题。

另一个小问题: COSArrayList.lastIndexOf使用包含列表的indexOf

已分析的PDFBox源是当前的3.0.0-SNAPSHOT,但所有版本2.0.0 - 2.0.7都会出现错误,因此它们的代码也很可能包含这些错误。