小智 5
该问题专门识别主题中的PDFBox库; 您不需要iText,可以使用PDFBox 1.8中提供的PDXFA对象完成XFA操作.
非常感谢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);
Run Code Online (Sandbox Code Playgroud)
这是我在分配问题时所能做的最好的事情。我将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();
}
Run Code Online (Sandbox Code Playgroud)
然后是为字段设置值的方法。我同时设置了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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
这项工作,但并非针对所有PDF生命周期的“种类”产生,有些人收到了有关“扩展功能”的警告消息,该消息已不再启用,但仍然有效。优化版本是我发现的唯一一个在填充后打开时不提示消息的版本。
我填写了XFA和Acroform,否则它不能在所有查看器中正常工作。
| 归档时间: |
|
| 查看次数: |
6892 次 |
| 最近记录: |