PDFBox 删除注释保留删除线

PDFBox delete comment maintain strikethrough

我有一个 PDF,其中有一段评论。这一段是划线的。我的要求是从特定页面删除命令。

以下代码应该从我的 PDF 中删除特定评论,但它没有。

PDDocument document = PDDocument.load(...File...);
List<PDAnnotation> 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<PDAnnotation> annotationToRemove = new ArrayList<PDAnnotation>();

    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);
    }
}

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

What is the best way to remove a specific comment and maintain a strikethrough on the text that the comment was appliaed?

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

可以这样做:

final COSName POPUP = COSName.getPDFName("Popup");

PDDocument document = PDDocument.load(resource);
List<PDAnnotation> annotations = new ArrayList<>();
PDPageTree allPages = document.getDocumentCatalog().getPages();

List<COSObjectable> 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 测试 testRemoveLikeStephanImproved)


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

page.getAnnotations()返回的页面注释列表是COSArrayList的实例。此 class 包含出现在页面 Annots 数组中的 COS 对象列表和这些条目的包装器列表(解析间接引用后 必要时)。

removeAll 方法(明智地)检查其参数集合以查找此类包装器,并从前一个集合中删除实际的 COS 对象,而不是包装器,并按原样(即带有包装器)从后者。

这适用于 Annots 数组中的直接对象,但由于代码试图删除 解决了个注释字典,而该列表实际上包含间接引用。

在手头的案例中,导致删除的内容没有被写回。在更一般的情况下,结果甚至会更奇怪,因为现在两个列表的大小不同。因此,面向索引的方法现在可以操作列表的非对应对象...

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

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

另一个故障:COSArrayList.lastIndexOf 使用包含列表的 indexOf

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