PDFBox表单填写-saveIncremental不起作用 [英] PDFBox Form fill - saveIncremental does not work

查看:155
本文介绍了PDFBox表单填写-saveIncremental不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个PDF文件,其中包含一些我想从Java中填写的表单字段.现在,我正在尝试只填写一张我要查找的表格,其名称就是该表格.我的代码如下:

I have a pdf file with some form field that I want to fill from java. Right now I'm trying to fill just one form which I am finding by its name. My code looks like this:

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

和这个:

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

作为system.out状态,该值已正确设置,但是在新生成的pdf文件中,未显示新值(显示了原始字符串),因此我猜想增量保存无法正常工作.我想念什么?

As system.out states, the value was set correctly, but in new the generated pdf file, new value is not showing up (original String is presented) so I guess the incremental saving does not work properly. What am I missing?

我使用pdfbox的2.0.2版本,这是我使用的pdf文件: pdf

I use 2.0.2 version of pdfbox, and here is pdf file with which I working: pdf

推荐答案

一般而言

当使用PDFBox 2.0.x将对PDF的更改保存为增量更新时,必须为每个更改的PDF对象将属性NeedToBeUpdated设置为true.此外,必须通过引用链可以从PDF目录访问该对象,并且该链中的每个PDF对象还必须将属性NeedToBeUpdated设置为true.

In general

When saving changes to a PDF as an incremental update with PDFBox 2.0.x, you have to set the property NeedToBeUpdated to true for every PDF object changed. Furthermore, the object must be reachable from the PDF catalog via a chain of references, and each PDF object in this chain also has to have the property NeedToBeUpdated set to true.

这是由于PDFBox增量保存的方式所致,它从目录开始检查NeedToBeUpdated属性,如果将其设置为true,则PDFBox会存储对象,并且只有在这种情况下,它才会更深地递归到在搜索更多要存储的对象时,从该对象引用的对象.

This is due to the way PDFBox saves incrementally, starting from the catalog it inspects the NeedToBeUpdated property, and if it is set to true, PDFBox stores the object, and only in this case it recurses deeper into the objects referenced from this object in search for more objects to store.

特别是,这意味着不必要地将某些对象标记为NeedToBeUpdated,例如PDF目录本身,在某些情况下甚至无法实现增量更新的目的,请参见下文.

In particular this implies that some objects unnecessarily have to be marked NeedToBeUpdated, e.g. the PDF catalog itself, and in some cases this even defeats the purpose of the incremental update at large, see below.

一方面,必须扩展setField方法,以将字段字典链标记为已更改的字段以及外观,包括该字段:

On one hand one has to extend the setField method to mark the chain of field dictionaries up to and including the changed field and also the appearance:

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 
}

(另一方面,必须扩展主要代码以标记从目录到fields数组的链:

On the other hand the main code has to be extended to mark a chain from the catalog to the fields array:

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

(当心:要与通用PDF一起使用,显然应该引入一些null测试...

Beware: for use with generic PDFs one obviously should introduce some null tests...

不幸的是,在Adobe Reader中打开结果文件会发现该程序抱怨更改会禁用文件中的扩展功能.

Opening the result file in Adobe Reader one will unfortunately see that the program complains about changes which disable extended features in the file.

这是由于PDFBox的增量保存中的古怪之处,它在更新部分中需要一些不必要的对象.特别是,目录保存在其中,其中包含使用权签名(授予扩展功能的技术).重新保存的签名显然不在其原始修订版中的原始位置了.因此,是无效的.

This is due to the quirk in PDFBox' incremental saving that it requires some unnecessary objects in the update section. In particular the catalog is saved there which contains a usage rights signature (the technology granting extended features). The re-saved signature obviously is not at its original position in its original revision anymore. Thus, is invalidated.

OP OP很可能希望增量保存PDF,以破坏该签名,但PDFBox不允许这样做.哦,好吧...

Most likely the OP OP wanted to save the PDF incrementally to not break this signature but PDFBox does not permit this. Oh well...

因此,唯一可以做的就是通过完全删除签名来防止警告.

Thus, the only thing one can do is prevent the warning by completely removing the signature.

我们已经在上面的补充中检索了目录对象,因此删除签名很容易:

We already have retrieved the catalog object in the additions above, so removing the signature is easy:

COSDictionary dictionary = document.getDocumentCatalog().getCOSObject();
// vvv--- new 
dictionary.removeItem(COSName.PERMS);
// ^^^--- new 
dictionary.setNeedToBeUpdated(true);

(不幸的是,在Adobe Reader中打开结果文件会发现该程序抱怨文件中缺少扩展功能来保存它.

Opening the result file in Adobe Reader one will unfortunately see that the program complains about missing extended features in the file to save it.

这是由于Adobe Reader需要扩展功能才能将更改保存到XFA表单的事实,这是我们在此步骤中必须删除的扩展功能.

This is due to the fact that Adobe Reader requires extended features to save changes to XFA forms, extended features we had to remove in this step.

但是手头的文档是混合的AcroForm& XFA表单文档,并且Adobe Reader不需要扩展功能即可保存AcroForm文档.因此,我们要做的就是删除XFA表单.由于我们的代码仅设置AcroForm值,所以这还是个好主意...

But the document at hand is a hybrid AcroForm & XFA form document, and Adobe Reader requires no extended features to save AcroForm documents. Thus, all we have to do is remove the XFA form. As our code only sets the AcroForm value, this is a good idea anyways...

我们已经在上面的补充中检索了acroform对象,因此从那里删除引用的XFA表单很容易:

We already have retrieved the acroform object in the additions above, so removing the XFA form referenced from there is easy:

dictionary = (COSDictionary) dictionary.getDictionaryObject(COSName.ACRO_FORM);
// vvv--- new 
dictionary.removeItem(COSName.XFA);
// ^^^--- new 
dictionary.setNeedToBeUpdated(true);

(在Adobe Reader中打开结果文件,您会发现现在可以不用再编辑表单并保存文件了.

Opening the result file in Adobe Reader one will see that one now can without further ado edit the form and save the file.

请注意,为此需要一个足够新的Adobe Reader版本,即使是将更改保存到AcroForm表单,早期版本(至少为版本9)确实需要扩展功能.

Beware, a sufficiently new Adobe Reader version is required for this, earlier versions (up to at least version 9) did require extended features even for saving changes to an AcroForm form

这篇关于PDFBox表单填写-saveIncremental不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆