我有一个pdf文件,其中包含一些我希望从java填写的表单字段.现在我正试图填写一个我正在寻找的形式.我的代码看起来像这样:
File file = new File("c:/Testy/luxmed/Skierowanie3.pdf");
PDDocument document = PDDocument.load(file);
PDDocumentCatalog doc = document.getDocumentCatalog();
PDAcroForm Form = doc.getAcroForm();
String formName = "topmostSubform[0].Page1[0].pana_pania[0]";
PDField f = Form.getField(formName);
setField(document, formName, "Artur");
System.out.println("New value 2nd: " + f.getValueAsString());
document.saveIncremental(new FileOutputStream("c:/Testy/luxmed/nowy_pd3.pdf"));
document.close();
Run Code Online (Sandbox Code Playgroud)
还有这个:
public static void setField(PDDocument pdfDocument, String name, String Value) throws IOException
{
PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
PDField field = acroForm.getField(name);
if (field instanceof PDCheckBox){
field.setValue("Yes");
}
else if (field instanceof PDTextField){
System.out.println("Original value: " + field.getValueAsString());
field.setValue(Value);
System.out.println("New value: " + field.getValueAsString());
}
else{
System.out.println("Nie znaleziono pola");
}
}
Run Code Online (Sandbox Code Playgroud)
正如system.out所述,值已正确设置,但在新生成的pdf文件中,新值未显示(显示原始字符串),因此我猜增量保存不能正常工作.我错过了什么?
我使用的是pdfbox的2.0.2版本,这里是我工作的pdf文件:pdf
将PDF的更改保存为PDFBox 2.0.x的增量更新时,必须将属性NeedToBeUpdated设置true为更改的每个PDF对象.此外,必须通过一系列引用从PDF目录中访问该对象,并且此链中的每个PDF对象也必须将属性NeedToBeUpdated设置为true.
这是由于PDFBox以增量方式保存的方式,从它检查NeedToBeUpdated属性的目录开始,如果设置为true,PDFBox存储该对象,并且仅在这种情况下,它会更深入地处理从此对象引用的对象以搜索更多内容要存储的对象.
特别是这意味着必须不必要地标记某些对象NeedToBeUpdated,例如PDF目录本身,并且在某些情况下,这甚至会破坏增量更新的目的,见下文.
NeedToBeUpdated属性一方面,必须扩展setField方法以标记字段链字典,包括更改的字段以及外观:
public static void setField(PDDocument pdfDocument, String name, String Value) throws IOException
{
PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
PDField field = acroForm.getField(name);
if (field instanceof PDCheckBox) {
field.setValue("Yes");
}
else if (field instanceof PDTextField) {
System.out.println("Original value: " + field.getValueAsString());
field.setValue(Value);
System.out.println("New value: " + field.getValueAsString());
}
else {
System.out.println("Nie znaleziono pola");
}
// vvv--- new
COSDictionary fieldDictionary = field.getCOSObject();
COSDictionary dictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.AP);
dictionary.setNeedToBeUpdated(true);
COSStream stream = (COSStream) dictionary.getDictionaryObject(COSName.N);
stream.setNeedToBeUpdated(true);
while (fieldDictionary != null)
{
fieldDictionary.setNeedToBeUpdated(true);
fieldDictionary = (COSDictionary) fieldDictionary.getDictionaryObject(COSName.PARENT);
}
// ^^^--- new
}
Run Code Online (Sandbox Code Playgroud)
(FillInFormSaveIncremental方法setField)
另一方面,必须扩展主代码以标记从目录到fields数组的链:
PDDocument document = PDDocument.load(...);
PDDocumentCatalog doc = document.getDocumentCatalog();
PDAcroForm Form = doc.getAcroForm();
String formName = "topmostSubform[0].Page1[0].pana_pania[0]";
PDField f = Form.getField(formName);
setField(document, formName, "Artur");
System.out.println("New value 2nd: " + f.getValueAsString());
// vvv--- new
COSDictionary dictionary = document.getDocumentCatalog().getCOSObject();
dictionary.setNeedToBeUpdated(true);
dictionary = (COSDictionary) dictionary.getDictionaryObject(COSName.ACRO_FORM);
dictionary.setNeedToBeUpdated(true);
COSArray array = (COSArray) dictionary.getDictionaryObject(COSName.FIELDS);
array.setNeedToBeUpdated(true);
// ^^^--- new
document.saveIncremental(new FileOutputStream(...));
document.close();
Run Code Online (Sandbox Code Playgroud)
(FillInFormSaveIncremental测试testFillInSkierowanie3)
注意:与通用PDF一起使用时,显然应该引入一些null测试......
不幸的是,在Adobe Reader中打开结果文件会看到程序抱怨有关禁用文件中扩展功能的更改.
这是由于PDFBox的增量保存中的怪癖,它需要更新部分中的一些不必要的对象.特别是目录保存在那里,其中包含使用权签名(授予扩展功能的技术).重新保存的签名显然不再处于原始版本的原始位置.因此,无效.
很可能OP OP想要逐步保存PDF以不破坏此签名,但PDFBox不允许这样做.那好吧...
因此,唯一能做的就是通过完全删除签名来防止警告.
我们已经在上面的附加内容中检索了目录对象,因此删除签名很容易:
COSDictionary dictionary = document.getDocumentCatalog().getCOSObject();
// vvv--- new
dictionary.removeItem(COSName.PERMS);
// ^^^--- new
dictionary.setNeedToBeUpdated(true);
Run Code Online (Sandbox Code Playgroud)
(FillInFormSaveIncremental测试testFillInSkierowanie3)
不幸的是,在Adobe Reader中打开结果文件会发现该程序抱怨文件中缺少扩展功能以保存它.
这是因为Adobe Reader需要扩展功能来保存对XFA表单的更改,我们必须在此步骤中删除扩展功能.
但是,手头的文档是混合的AcroForm和XFA表单文档,Adobe Reader不需要扩展功能来保存AcroForm文档.因此,我们所要做的就是删除XFA表单.因为我们的代码只设置了AcroForm值,所以无论如何这都是个好主意......
我们已经在上面的添加中检索了acroform对象,因此从那里删除引用的XFA表单很容易:
dictionary = (COSDictionary) dictionary.getDictionaryObject(COSName.ACRO_FORM);
// vvv--- new
dictionary.removeItem(COSName.XFA);
// ^^^--- new
dictionary.setNeedToBeUpdated(true);
Run Code Online (Sandbox Code Playgroud)
(FillInFormSaveIncremental测试testFillInSkierowanie3)
在Adobe Reader中打开结果文件将看到现在可以不用再编辑表单并保存文件了.
请注意,这需要一个足够新的Adobe Reader版本,早期版本(至少版本9)确实需要扩展功能,即使保存对AcroForm表单的更改也是如此
| 归档时间: |
|
| 查看次数: |
1363 次 |
| 最近记录: |