首页 文章

如何使用iTextSharp正确填写XFA表单数据,以便在Acrobat XI中编辑和保存结果

提问于
浏览
0

我有一个应用程序,我正在使用iTextSharp填充pdf表单 .

/// <summary>
    /// Imports XFA Data into a new PDF file.
    /// </summary>
    /// <param name="pdfTemplate">A PDF File with an unpopulated form.</param>
    /// <param name="xmlFormData">XFA form data in XML format.</param>
    /// <returns>a memorystream containing the new PDF file.</returns>
    public static void XFAImport(System.IO.Stream pdfTemplate, System.IO.Stream xmlFormData, System.IO.Stream outputStream)
    {
        using (iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader(pdfTemplate))
        {
            using (iTextSharp.text.pdf.PdfStamper stamper = new iTextSharp.text.pdf.PdfStamper(reader, outputStream))
            {
                stamper.Writer.CloseStream = false;
                stamper.AcroFields.Xfa.FillXfaForm(xmlFormData);
            }
        }
    }

上面的代码采用未填写的pdf格式和xml数据并写入outputStream,然后将其保存到文件中 .

在Adobe中打开文件时,您会看到正确填写的表单数据 . 但是,如果您随后从Acrobat XI保存该文件,然后重新打开该文件,则导入的数据将不再可见 .

我不相信我要导入的XML问题,因为如果不是使用iTextShart,而是使用Acrobat XI的“工具/表单/更多表单选项/导入数据” . 生成的文件可以保存并正确重新打开 .

我的问题是:

我上面正确使用PdfStamper吗?

是否有任何步骤可以使生成的文件正确保存?

PS . 我注意到,在使用Acrobat XI重新保存输出pdf文件后,生成的文件与原始文件大致相同,但最后还插入了11k的数据 .

输出pdf文件的结尾:

trailer
<</Size 51/Root 14 0 R/Info 3 0 R/ID [<56549fdaf0c5ab4e9321d77f406e6455><5b60738018e0cdac94c6d1b924fc8bed>]>>
%iText-5.4.4
startxref
529008
%%EOF

在Acrobat XI中保存后,添加了更多数据:

trailer
<</Size 51/Root 14 0 R/Info 3 0 R/ID [<56549fdaf0c5ab4e9321d77f406e6455>         <5b60738018e0cdac94c6d1b924fc8bed>]>>
%iText-5.4.4
startxref
529008
%%EOF
3 0 obj
<</CreationDate(D:20100120124725-05'00')/Creator(Adobe LiveCycle Designer ES 8.2)/ModDate(D:20140221145558-06'00')/Producer(Adobe LiveCycle Designer ES 8.2; modified using iTextSharp’ 5.4.4 ©2000-2013 1T3XT BVBA \(AGPL-version\))>>
endobj
4 0 obj
<</Length 3261/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>

/*more data excluded*/

3 回答

  • 3

    不,您没有正确使用 PdfStamper .

    使用数字签名实现读者启用(它需要Adobe提供的私钥) . 当您使用"standard way"填写表单时,您将破坏该签名 . 您需要填写 append mode 中的表格 .

    我在我的书的第8.7.2节中解释了这一点,题为"Filling out Reader-enabled forms using iText"(它打败了我为什么在提出问题之前没有人阅读文档;人们想知道为什么甚至会困扰写一本书) . 您可以在此处找到此部分附带的示例:ReaderEnabledForm

    您可以在on SourceForge的相应章节中找到C#版本:

    底线:你需要更换

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

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

    在这种情况下,您的更改将附加在 %%EOF 标记之后,并且Adobe应用的数字签名不会被破坏 .

  • 0

    谢谢你的提示 . 这就是我们最终做的事情(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
    
  • 0

    实际上,上面的代码在我们以编程方式填充部分内容后需要手动输入数据的人员时会出现一些问题 . 我们的XFA表单有10个步骤,我们只填充前两个步骤 . 试图对后续步骤进行数字签名的人看到了一条错误消息,声称“dataModel没有方法'克隆' . ”无论如何,我们最终直接填充表单字段,跳过了使用外部XML的需要 . 这解决了我们的问题 .

    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
    

相关问题