This is the best I could manage at the time I was assigned to this problem. I get PDF (in the life cycle) as optimized (I'm not the one who makes PDF). This is part of opening the PDF, duplicating the XML, and then saving:
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(); }
then the methods that set the values ​​for the fields. I installed both XFA and 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 {
This work, but not for all “views” of the PDF life cycle, some of them received a warning message about the “extended fonction”, which is no longer included, but still works. The optimized version is the only one I found who does not request a message when it opens after filling.
I fill out XFA and Acroform, otherwise it doesn't work in all viewers.
source share