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



我有一个应用程序,我正在使用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保存该文件,然后重新打开它,则导入的数据将不再可见。

生成的文件能够正确保存和重新打开。

我的问题是:

我是否正确使用了上面的PdfStamper?

我可以采取哪些步骤来正确保存生成的文件吗?

PS。我注意到,在使用Acrobatneneneba 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

保存在Acrobatneneneba 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*/

否,您没有正确使用PdfStamper

阅读器启用是通过数字签名实现的(它需要Adobe的私钥)。当你用"标准方式"填写表格时,你就破坏了签名。您需要在附加模式中填写表格。

我在我的书的第8.7.2节中解释了这一点,题为"使用iText填写启用阅读器的表格"(我很难理解为什么没有人在提问之前阅读过文档;人们想知道为什么有人会麻烦写书)。您可以在此处找到本节附带的示例:ReaderEnabledForm

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

一句话:你需要更换

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

带有

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

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

感谢您的提示。这就是我们最终要做的(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, "", 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

实际上,上面的代码给那些需要在我们以编程方式填充部分数据后手动在表单中输入数据的人带来了一些问题。我们的XFA表单有大约10个步骤,其中我们只填充前2个步骤。试图对后面的步骤进行数字签名的人看到了一条错误消息,上面写着"dataModel没有方法‘clone’。"无论如何,我们最终直接填充了表单字段,跳过了使用外部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, "", 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

最新更新