Combining XFA with PDFBox

I would like to fill out a PDF form using the PDFBox java library. The PDF form is created using Adobe Live Designer, so it uses the XFA format.

I am trying to find resources on filling out XFA PDF forms using PDFBox, but so far I have been out of luck. I saw that the PDAcroForm.setXFA method is available in the API, but I don’t see how to use it.

Do you know that you can fill out a PDF PDFbox form? If so, is there a sample code or tutorial somewhere to achieve this? If not, what are the best alternatives to achieve this?

+4
source share
4 answers

The question specifically defines the PDFBox library in the subject; you don't need iText, XFA manipulation can be done using the PDXFA object available in PDFBox 1.8.

Many thanks to Marouan Sahyun for his great work on PDFBox + XFA.

This code only works when removing all security on a PDDocument.
It also assumes that the COS object in the PDXFA is a COSStream. The simplest example below reads an xml stream and writes it back to 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); 
+5
source

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 { // 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)); } } } 

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.

+3
source

I am not familiar with pdfbox, but you can do it with iText ( http://itextpdf.com/ ) as soon as you access the XFA (XML) DOM.

+2
source

AcroForm for PDF with static fields. If the PDF has xfa forms, you can use itext (Java) or itextsharp (.net) to populate your data. The only problem with XFA forms is that they cannot be Flatten with itext only in the Flatten way that I found using bullzip or a similar PDF creator to open this xfa pdf created with itext and pass it through bullzip, which will spit out smooth out the pdf version. Hope this gives you some ideas.

Below is just a rough idea of ​​how xfa is populated.

 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); 

now you can use the created xfa pdf and print via bullzip

const string Printer_Name = "Bullzip PDF Printer";

  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); 

output file will be smoothed pdf.

-1
source

Source: https://habr.com/ru/post/1411802/


All Articles