我想用 PDFBox java 库填写 PDF 表单。PDF 表单是使用 Adobe Live Designer 创建的,因此它使用 XFA 格式。
我尝试查找有关使用 PDFBox 填写 XFA PDF 表单的资源,但到目前为止我还没有运气。我看到 API 中提供了一个 PDAcroForm.setXFA 方法,但我不知道如何使用它。
您知道是否可以使用 PDFBox 填写 PDF 表单?如果是,是否有任何代码示例或教程可以实现这一目标?如果不是,实现这一目标的最佳选择是什么?
这是我在被分配解决问题时能够管理的最好的。我将 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,否则它不适用于所有查看器。
该问题专门标识了该主题中的 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);
我对 pdfbox 不熟悉,但您可以在访问 XFA (XML) DOM 后使用 iText ( http://itextpdf.com/ ) 执行此操作。
试试这个,它将合并所有没有 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);
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 ..