为什么我的表单在没有调用flattenFields方法的情况下被展平?

时间:2017-11-30 20:09:09

标签: java pdf itext7

我正在使用此表单https://help.adobe.com/en_US/Acrobat/9.0/Samples/interactiveform_enabled.pdf

测试我的方法

它被称为:

Pdf.editForm("./src/main/resources/pdfs/interactiveform_enabled.pdf", "./src/main/resources/pdfs/FILLEDOUT.pdf"));

其中Pdf只是一个工人类,而editForm是一个静态方法。

editForm方法如下所示:

public static int editForm(String inputPath, String outputPath) {
    try {
        PdfDocument pdf = new PdfDocument(new PdfReader(inputPath), new PdfWriter(outputPath));
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
        Map<String, PdfFormField> m = form.getFormFields();
        for (String s : m.keySet()) {
            if (s.equals("Name_First")) {
                m.get(s).setValue("Tristan");
            }
            if (s.equals("BACHELORS DEGREE")) {
                m.get(s).setValue("Off"); // On or Off
            }
            if (s.equals("Sex")) {
                m.get(s).setValue("FEMALE");
            }
            System.out.println(s);
        }
        pdf.close();
        logger.info("Completed");
    } catch (IOException e) {
        logger.error("Unable to fill form " + outputPath + "\n\t" + e);
        return 1;
    }

    return 0;
}

不幸的是,调用此方法后,FILLEDOUT.pdf文件不再是表单。我做错了吗?

我使用this资源作为指导。请注意我不是在调用form.flattenFields()。但是,如果我确实调用了该方法,则会收到java.lang.IllegalArgumentException的错误。

感谢您的时间。

2 个答案:

答案 0 :(得分:2)

您的表单启用了阅读器,即它包含Adobe发布的密钥和证书的使用权数字签名,以向常规Adobe Reader表明,当使用该PDF时,它将激活许多其他功能。< / p>

如果您在原始代码中标记文件,现有的PDF对象将重新排列并稍作更改。这打破了使用权签名,Adobe Reader认识到这一点,并且声明文件已被更改,因为文档已经创建并且不再使用扩展功能。&#34;

如果您在追加模式中标记文件,则更改将作为增量更新附加到PDF。因此,签名仍然正确地标记其原始字节范围,Adobe Reader不会抱怨。

要激活追加模式,请在创建StampingProperties时使用PdfDocument

PdfDocument pdf = new PdfDocument(new PdfReader(inputPath), new PdfWriter(outputPath), new StampingProperties().useAppendMode());

(使用iText 7.1.1-SNAPSHOT和Adobe Acrobat Reader DC版本2018.009.20050测试)

顺便说一句,Adobe Reader不仅会检查签名,还会尝试确定增量更新中的更改是否超出了使用权签名激活的其他功能的范围。

否则,你可以简单地使用一个支持Reader的小PDF,并在附加模式下用你自己选择的内容替换所有现有页面。这当然不符合Adobe的兴趣...

答案 1 :(得分:1)

填写的PDF仍然是AcroForm,否则下面的示例将导致相同的PDF两次。

public class Main {
public static final String SRC = "src/main/resources/interactiveform_enabled.pdf";
public static final String DEST = "results/filled_form.pdf";
public static final String DEST2 = "results/filled_form_second_time.pdf";

public static void main(String[] args) throws Exception {
    File file = new File(DEST);
    file.getParentFile().mkdirs();
    Main main = new Main();

    Map<String, String> data1 = new HashMap<>();
    data1.put("Name_First", "Tristan");
    data1.put("BACHELORS DEGREE", "Off");
    main.fillPdf(SRC, DEST, data1, false);

    Map<String, String> data2 = new HashMap<>();
    data2.put("Sex", "FEMALE");
    main.fillPdf(DEST, DEST2, data2, false);
}

private void fillPdf(String src, String dest, Map<String, String> data, boolean flatten) {
    try {
        PdfDocument pdf = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);

        //Delete print field from acroform because it is defined in the contentstream not in the formfields
        form.removeField("Print");

        Map<String, PdfFormField> m = form.getFormFields();

        for (String d : data.keySet()) {
            for (String s : m.keySet()) {
                if(s.equals(d)){
                    m.get(s).setValue(data.get(d));
                }
            }
        }

        if(flatten){
            form.flattenFields();
        }

        pdf.close();
        System.out.println("Completed");
    } catch (IOException e) {
        System.out.println("Unable to fill form " + dest + "\n\t" + e);
    }
}
}

您面临的问题与“已启用阅读器的表单”有关。 它归结为最初提供给您的程序的PDF文件是读取器启用。因此,您可以在Adobe Reader中打开PDF并填写表格。这允许Acrobat用户扩展Adobe Reader的行为。 一旦使用iText填写并关闭PDF,它就会将PDF保存为“不是读者扩展的”。 这使得AcroForm仍然可以使用iText填充,但是当您使用Adobe Reader打开PDF时,您在原始PDF中看到的扩展功能已经消失。但这并不意味着形式被夷为平地。

iText无法启用表单阅读器,事实上,创建已启用阅读器的表单的唯一方法是使用Acrobat Professional。这就是Acrobat和Adobe Reader的互动方式,而不是iText可以模仿或解决的问题。您可以在link上找到更多信息和可能的解决方案。

调用form.flattenFields()方法时得到的IllegalArgumentException是由于PDF文档的构造方式。 &#34;打印表格&#34;按钮应该已在AcroForm中定义,但它在PDF的内容流中定义,这意味着AcroForm中的按钮具有空文本值,这就是导致异常的原因。

您可以通过在展平之前从AcroForm中删除打印字段来解决此问题。