8

我想用 PDFBox java 库填写 PDF 表单。PDF 表单是使用 Adob​​e Live Designer 创建的,因此它使用 XFA 格式。

我尝试查找有关使用 PDFBox 填写 XFA PDF 表单的资源,但到目前为止我还没有运气。我看到 API 中提供了一个 PDAcroForm.setXFA 方法,但我不知道如何使用它。

您知道是否可以使用 PDFBox 填写 PDF 表单?如果是,是否有任何代码示例或教程可以实现这一目标?如果不是,实现这一目标的最佳选择是什么?

4

5 回答 5

8

这是我在被分配解决问题时能够管理的最好的。我将 pdf 保存为优化(在生命周期中)(我不是做 pdf 的人)。这是PDF打开部分,XML复制然后保存:

    PDDocument document = PDDocument.load(fileInputStream);
    fileInputStream.close();
    document.setAllSecurityToBeRemoved(true);

    Map<String, String> values = new HashMap<String, String>();
    values.put("variable_name", "value");


    setFields(document, values); // see code below

    PDAcroForm form = document.getDocumentCatalog().getAcroForm();
    Document documentXML = form.getXFA().getDocument();

    NodeList dataElements = documentXML.getElementsByTagName("xfa:data");
    if (dataElements != null) {
        for (int i = 0; i < dataElements.getLength(); i++) {
            setXFAFields(dataElements.item(i), values);
        }
    }

    COSStream cosout = new COSStream(new RandomAccessBuffer());

    TransformerFactory.newInstance().newTransformer()
            .transform(new DOMSource(documentXML), new StreamResult(cosout.createUnfilteredStream()));

    form.setXFA(new PDXFA(cosout));

    FileOutputStream fios = new FileOutputStream(new File(docOut + ".pdf"));
    document.save(fios);
    document.close();
    try {
        fios.flush();
    } finally {
        fios.close();
    }

然后是为字段设置值的方法。我设置了 XFA 和 AcroForm:

public void setXFAFields(Node pNode, Map<String, String> values) throws IOException {
    if (values.containsKey(pNode.getNodeName())) {
        pNode.setTextContent(values.get(pNode.getNodeName()));
    } else {
        NodeList childNodes = pNode.getChildNodes();
        if (childNodes != null) {
            for (int i = 0; i < childNodes.getLength(); i++) {
                setXFAFields(childNodes.item(i), values);
            }
        }
    }
}

public void setFields(PDDocument pdfDocument, Map<String, String> values) throws IOException {

    @SuppressWarnings("unchecked")
    List<PDField> fields = pdfDocument.getDocumentCatalog().getAcroForm().getFields();
    for (PDField pdField : fields) {
        setFields(pdField, values);
    }
}

private void setFields(PDField field, Map<String, String> values) throws IOException {
    List<COSObjectable> kids = field.getKids();
    if (kids != null) {
        for (COSObjectable pdfObj : kids) {
            if (pdfObj instanceof PDField) {
                setFields((PDField) pdfObj, values);
            }
        }
    } else {
        // remove the [0] from the name to match values in our map
        String partialName = field.getPartialName().replaceAll("\\[\\d\\]", "");
        if (!(field instanceof PDSignatureField) && values.containsKey(partialName)) {
            field.setValue(values.get(partialName));
        }
    }
}

这项工作,但不适用于所有“种类”的 PDF 生命周期产品,有些人收到关于“扩展功能”不再启用但仍然有效的警告消息。优化版是我发现的唯一一个填充后打开不提示信息的。

我填充了 XFA 和 Acroform,否则它不适用于所有查看器。

于 2014-11-28T19:32:09.270 回答
6

该问题专门标识了该主题中的 PDFBox 库;您不需要 iText,XFA 操作可以使用 PDFBox 1.8 中可用的 PDXFA 对象来完成。

非常感谢 Maruan Sahyoun 在 PDFBox + XFA 上的出色工作。

仅当您删除 PDDocument 上的所有安全性时,此代码才有效。
它还假设 PDXFA 中的 COS 对象是一个 COSStream。下面的简单示例读取 xml 流并将其写回 PDF。

 PDDocument doc = PDDocument.load("filename");
 doc.setAllSecurityToBeRemoved(true);

 PDDocumentCatalog docCatalog = doc.getDocumentCatalog();
 PDAcroForm form = docCatalog.getAcroForm();

 PDXFA xfa = form.getXFA();
 COSBase cos = xfa.getCOSObject();
 COSStream coss = (COSStream) cos;
 InputStream cosin = coss.getUnfilteredStream();
 Document document = documentBuilder.parse(cosin);

 COSStream cosout = new COSStream(new RandomAccessBuffer());
 OutputStream out = cosout.createUnfilteredStream();

 TransformerFactory tFactory = TransformerFactory.newInstance();
 Transformer transformer = tFactory.newTransformer();
 DOMSource source = new DOMSource(xmlDoc);
 StreamResult result = new StreamResult(out);
 transformer.transform(source, result);

 PDXFA xfaout = new PDXFA(cosout);
 form.setXFA(xfaout);
于 2014-01-16T17:47:13.490 回答
1

我对 pdfbox 不熟悉,但您可以在访问 XFA (XML) DOM 后使用 iText ( http://itextpdf.com/ ) 执行此操作。

于 2012-05-16T19:20:24.633 回答
0

试试这个,它将合并所有没有 xfa 和 XFA 的 pdf(这是仅使用 PDBox 时)


PDAcroForm form = document.getDocumentCatalog().getAcroForm();
 if(form != null) {
      document.setAllSecurityToBeRemoved(true);
      form.flatten();
      if(form.hasXFA()) {
         form.setXFA(null);
      }
 }                       
 merge.appendDocument(anyPDFDoc, document);
于 2020-09-08T16:04:29.730 回答
-2

AcroForm 用于带有静态字段的 PDF。如果 PDF 有 xfa 表单,您可以使用 itext (Java) 或 itextsharp (.net) 来填充您的数据。XFA 表单的唯一问题是它们不能用 itext 进行展平,我发现只有使用 Bullzip 或类似的 pdf 创建器来打开使用 itext 创建的 xfa pdf 并将其传递给 Bullzip,这将吐出展平的 pdf 版本。希望这会给你一些想法。

下面的代码只是一个粗略的想法 xfa 是如何填充的。

XfaForm xfa = pdfFormFields.Xfa;
dynamic bytes = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?> <form1> <staticform>" + "\r\n<barcode>" + barcode + "</barcode></staticform> <flowForm><Extra>" + Extra + "</Extra></flowForm> </form1>");
MemoryStream ms = new MemoryStream(bytes);
pdfStamper.AcroFields.Xfa.FillXfaForm(ms);

您现在可以使用您创建的 xfa pdf 并通过 Bullzip 打印

const string Printer_Name = "Bullzip PDF 打印机";

                    PdfSettings pdfSettings = new PdfSettings();
                    pdfSettings.PrinterName = Printer_Name;
                    pdfSettings.SetValue("Output", flatten_pdf);
                    pdfSettings.SetValue("ShowPDF", "no");
                    pdfSettings.SetValue("ShowSettings", "never");
                    pdfSettings.SetValue("ShowSaveAS", "never");
                    pdfSettings.SetValue("ShowProgress", "no");
                    pdfSettings.SetValue("ShowProgressFinished", "no");
                    pdfSettings.SetValue("ConfirmOverwrite", "no");
                    pdfSettings.WriteSettings(PdfSettingsFileType.RunOnce);
                    PdfUtil.PrintFile(xfa_pdffile, Printer_Name);

输出文件将被展平pdf ..

于 2012-12-06T16:55:35.230 回答