2012-05-10 90 views
4

我想用PDFBox Java庫填充PDF表單。 PDF表單使用Adobe Live Designer創建,因此它使用XFA格式。將XFA與PDFBox結合

我嘗試找到有關使用PDFBox填充XFA PDF表單的資源,但目前爲止我還沒有任何運氣。我看到API中有一個PDAcroForm.setXFA方法,但我不知道如何使用它。

你知道是否可以使用PDFBox填寫PDF表單嗎? 如果是的話,是否有任何代碼示例或教程來實現這一目標? 如果不是,那麼實現此目標的最佳選擇是什麼?

回答

2

我對pdfbox並不熟悉,但只要您能夠訪問XFA(XML)DOM,您就可以使用iText(http://itextpdf.com/)執行此操作。

+0

我終於選擇了itext。 – OutOfBound

-1

AcroForm是用於帶有靜態字段的PDF。如果PDF具有xfa形式,則可以使用itext(Java)或itextsharp(.net)來填充數據。只有XFA格式的問題是他們不能用itext壓扁Flatten我發現使用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); 

您現在可以使用您創建的PDF XFA通過的BullZip

常量字符串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 ..

+5

那麼,我們**總是**需要代碼。所以如果你能提供罐頭,就提供它。 – j0k

+0

這是標記爲Java的問題。 Bullzip不適用於Java! –

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

在上面的代碼中,「documentBuilder」是什麼? –

+0

我使用了上面的代碼,並且由於生成的文件非常大而引起了一點關注。 PDF文件以647kb pdf開始。新的pdf 14000kb。任何人都知道如何減少生成的新文件的大小。回寫到pdf文件時可以設置某種類型的壓縮嗎? – chamalabey

+0

JammyDodger代碼只顯示如何訪問XML以及如何恢復。不顯示如何查找字段,如何設置值... DocumentBuilder是一個javax.xml.parsers.DocumentBuilder,可以用javax.xml.parsers.DocumentBuilderFactory獲取,據我所見。未定義的變量xmlDoc是文檔(我的猜測) –

3

這是我在分配問題時能夠管理的最佳狀態。我將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生命週期生產的「種」,一些有關於「延長fonction」不再啓用,但仍然可以工作一個警告消息。優化版本是我發現的唯一一個在被填充後打開時不會提示消息的人。

我填充了XFA和Acroform,否則它不適用於所有查看器。