How to correctly fill in XFA form data using iTextSharp to allow editing and saving result in Acrobat XI

倖福魔咒の 提交于 2019-12-02 09:56:11

No, you are not using PdfStamper correctly.

Reader enabling is achieved using a digital signature (it requires a private key from Adobe). When you fill out the form using the "standard way", you break that signature. You need to fill out the form in append mode.

I've explained this in section 8.7.2 of my book, entitled "Filling out Reader-enabled forms using iText" (it beats me why nobody ever reads the documentation before asking a question; one wonders why one even bothers writing a book). You can find the example that comes with this section here: ReaderEnabledForm

You can find the C# version in of the corresponding chapter on SourceForge:

Bottom line: you need to replace

new iTextSharp.text.pdf.PdfStamper(reader, outputStream)

with

new iTextSharp.text.pdf.PdfStamper(reader, outputStream, '\0', true)

In this case, your changes will be appended after the %%EOF marker and the digital signature applied by Adobe won't be broken.

Thanks for the tips. This is what we ended up doing (VB.NET):

Public Shared Sub XFAImport(pdfTemplate As System.IO.Stream, xmlFormData As System.IO.Stream, outputStream As System.IO.Stream)
    ' Imports XFA Data into a new PDF file.
    ' pdfTemplate is PDF File with an unpopulated form
    ' xmlFormData is an XFA form data in XML format (the data we wish to enter)
    ' We get a memorystream containing the new PDF file

    Dim reader As New pdf.PdfReader(pdfTemplate)
    PdfReader.unethicalreading = True ' Allow reading a PDF file that is protected by a password

    Using reader
        Using stamper As New iTextSharp.text.pdf.PdfStamper(reader, outputStream, "\0", True)
            stamper.Writer.CloseStream = False
            stamper.AcroFields.Xfa.FillXfaForm(xmlFormData)
        End Using
    End Using
End Sub


Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim strErr As String = ""

    Dim afto22pdf As String = Server.MapPath("../AFTO22/afto22_protected.pdf")
    Dim newXml As String = Server.MapPath("../AFTO22/newxml1.xml")
    Dim newAfto22pdf As String = Server.MapPath("../AFTO22/newAfto22_protected.pdf")


    Dim pdfTemplate As New FileStream(afto22pdf, FileMode.Open, FileAccess.Read)
    Dim xmlFormData As New FileStream(newXml, FileMode.Open, FileAccess.Read)
    Dim outputStream As New FileStream(newAfto22pdf, FileMode.Create, FileAccess.Write)
    Try
        XFAImport(pdfTemplate, xmlFormData, outputStream)
    Catch ex As Exception
        strErr = "Error detected: " & ex.Message
    End Try

    Label1.Text = strErr.ToString

    outputStream.Close()
    pdfTemplate.Close()
    xmlFormData.Close()
    outputStream = Nothing
    pdfTemplate = Nothing
    xmlFormData = Nothing
End Sub

Actually, the code above caused some problems for people who needed to enter data in the form manually AFTER we populated part of it programmatically. Our XFA form has some 10 steps, where we populate only the first 2 steps. People trying to digitally sign later steps saw an error message, stating "dataModel does not have a method 'clone'." Anyhow, we ended up populating the form fields directly, skipping the need to use an external XML. This solved our problems.

Try
   Dim filename As String = Server.MapPath("../AFTO22/Afto22_populated.pdf")
   Dim pdfReader As New PdfReader(Server.MapPath("~/AFTO22/afto22.pdf"))
   pdfReader.unethicalreading = True

   Using stream As New FileStream(filename, FileMode.Create)
      Dim pdfStamper As New PdfStamper(pdfReader, stream, "\0", True)
      Dim formFields As AcroFields = pdfStamper.AcroFields
      formFields.SetField("FIELD1", "My Name")
      formFields.SetField("FIELD5", "My Rank")

      pdfStamper.FormFlattening = False
      pdfStamper.Close()
   End Using
Catch ex As Exception
   Label1.Text = ex.Message
End Try
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!