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,然后将其保存到文件中。

当您在 Adob​​e 中打开文件时,您会看到正确填写的表单数据。但是,如果您随后从 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*/
4

3 回答 3

3

不,你没有PdfStamper正确使用。

阅读器启用是使用数字签名实现的(它需要来自 Adob​​e 的私钥)。当您使用“标准方式”填写表格时,您会破坏该签名。您需要以附加模式填写表格。

我在我的书的第 8.7.2 节中对此进行了解释,题为“使用 iText 填写支持阅读器的表单”(这让我感到震惊,为什么没有人在提出问题之前阅读文档;有人想知道为什么有人甚至费心写一本书) . 您可以在此处找到本节附带的示例:ReaderEnabledForm

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

底线:您需要更换

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

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

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

于 2014-02-22T08:31:26.700 回答
0

实际上,上面的代码给那些需要在我们以编程方式填充部分数据后手动输入数据的人造成了一些问题。我们的 XFA 表单有大约 10 个步骤,我们只填充前 2 个步骤。尝试对后续步骤进行数字签名的人看到一条错误消息,指出“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

于 2017-08-24T16:21:15.557 回答
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
于 2017-08-01T07:28:55.387 回答