[英]Does PDFBox allow to remove one field from AcroForm?
I am using Apache PDFBox 2.0.8 and trying to remove one field. 我正在使用Apache PDFBox 2.0.8,并尝试删除一个字段。 But can not find the way to do it, like I can do with iText: PdfStamper.getAcroFields().removeField("signature3")
. 但是找不到方法,就像我可以使用iText一样: PdfStamper.getAcroFields().removeField("signature3")
。
What I am tying to do. 我想做的事。 Initially I have template PDF with 3 Digital Signatures. 最初,我有带有3个数字签名的PDF模板。 In some cases I need just 2 signatures, so it this case I need to remove 3rd signature from the template. 在某些情况下,我只需要2个签名,因此在这种情况下,我需要从模板中删除第3个签名。 And seems like I can't do it with PDFBox, close thing I found is flattening this field, but that problem is if a flatten particular PDField (not whole form, but just one field) - all other signatures are loosing their functionality, looks like they are getting flattened as well. 似乎我无法用PDFBox做到这一点,我发现关闭的东西正在使该字段扁平化,但是问题是,如果扁平化的特定PDField(不是整个表单,而是一个字段)-所有其他签名都失去了它们的功能,看起来就像他们也变得扁平一样。 Here is code that does it: 这是执行此操作的代码:
PDDocument document = PDDocument.load(file);
PDDocumentCatalog documentCatalog = document.getDocumentCatalog();
PDAcroForm acroForm = documentCatalog.getAcroForm();
List<PDField> flattenList = new ArrayList<>();
for (PDField field : acroForm.getFieldTree()) {
if (field instanceof PDSignatureField && "signature3".equals(field.getFullyQualifiedName())) {
flattenList.add(field);
}
}
acroForm.flatten(flattenList, true);
document.save(dest);
document.close();
As Tilman already mentioned in a comment, PDFBox doesn't have a method to remove a field from the field tree. 正如Tilman在评论中已经提到的那样, PDFBox没有从字段树中删除字段的方法。 Nonetheless it has methods to manipulate the underlying PDF structure, so one can write such a method oneself, eg like this: 尽管如此,它仍然具有操纵底层PDF结构的方法,因此人们可以自己编写这样的方法,例如:
PDField removeField(PDDocument document, String fullFieldName) throws IOException {
PDDocumentCatalog documentCatalog = document.getDocumentCatalog();
PDAcroForm acroForm = documentCatalog.getAcroForm();
if (acroForm == null) {
System.out.println("No form defined.");
return null;
}
PDField targetField = null;
for (PDField field : acroForm.getFieldTree()) {
if (fullFieldName.equals(field.getFullyQualifiedName())) {
targetField = field;
break;
}
}
if (targetField == null) {
System.out.println("Form does not contain field with given name.");
return null;
}
PDNonTerminalField parentField = targetField.getParent();
if (parentField != null) {
List<PDField> childFields = parentField.getChildren();
boolean removed = false;
for (PDField field : childFields)
{
if (field.getCOSObject().equals(targetField.getCOSObject())) {
removed = childFields.remove(field);
parentField.setChildren(childFields);
break;
}
}
if (!removed)
System.out.println("Inconsistent form definition: Parent field does not reference the target field.");
} else {
List<PDField> rootFields = acroForm.getFields();
boolean removed = false;
for (PDField field : rootFields)
{
if (field.getCOSObject().equals(targetField.getCOSObject())) {
removed = rootFields.remove(field);
break;
}
}
if (!removed)
System.out.println("Inconsistent form definition: Root fields do not include the target field.");
}
removeWidgets(targetField);
return targetField;
}
void removeWidgets(PDField targetField) throws IOException {
if (targetField instanceof PDTerminalField) {
List<PDAnnotationWidget> widgets = ((PDTerminalField)targetField).getWidgets();
for (PDAnnotationWidget widget : widgets) {
PDPage page = widget.getPage();
if (page != null) {
List<PDAnnotation> annotations = page.getAnnotations();
boolean removed = false;
for (PDAnnotation annotation : annotations) {
if (annotation.getCOSObject().equals(widget.getCOSObject()))
{
removed = annotations.remove(annotation);
break;
}
}
if (!removed)
System.out.println("Inconsistent annotation definition: Page annotations do not include the target widget.");
} else {
System.out.println("Widget annotation does not have an associated page; cannot remove widget.");
// TODO: In this case iterate all pages and try to find and remove widget in all of them
}
}
} else if (targetField instanceof PDNonTerminalField) {
List<PDField> childFields = ((PDNonTerminalField)targetField).getChildren();
for (PDField field : childFields)
removeWidgets(field);
} else {
System.out.println("Target field is neither terminal nor non-terminal; cannot remove widgets.");
}
}
( RemoveField helper methods removeField
and removeWidgets
) ( RemoveField辅助方法removeField
和removeWidgets
)
One can apply this to a document and field like this: 可以这样将其应用于文档和字段:
PDDocument document = PDDocument.load(SOURCE_PDF);
PDField field = removeField(document, "Signature1");
Assert.assertNotNull("Field not found", field);
document.save(TARGET_PDF);
document.close();
( RemoveField test testRemoveInvisibleSignature
) ( RemoveField测试testRemoveInvisibleSignature
)
PS: I am not sure how much form related information PDFBox actually caches somewhere. PS:我不确定PDFBox实际在某处缓存了多少与表格相关的信息。 Thus, I would propose not to manipulate the form information any further in the same document manipulation session, at least not without tests. 因此,我建议至少在没有测试的情况下,不要在同一文档操作会话中进一步操作表单信息。
PPS: You find a TODO in the removeWidgets
helper method. PPS:您可以在removeWidgets
帮助器方法中找到一个TODO。 If the method outputs "Widget annotation does not have an associated page; cannot remove widget" , you'll have to add the missing code. 如果该方法输出“窗口小部件注释没有关联的页面;无法删除窗口小部件” ,则必须添加缺少的代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.