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 的所有版本都会出现错误,因此他们的代码很可能也包含这些错误。
我有一个 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 的所有版本都会出现错误,因此他们的代码很可能也包含这些错误。