Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 如何使用iTextSharp将PDF与可填充表单字段组合/合并?_.net_Itextsharp - Fatal编程技术网

.net 如何使用iTextSharp将PDF与可填充表单字段组合/合并?

.net 如何使用iTextSharp将PDF与可填充表单字段组合/合并?,.net,itextsharp,.net,Itextsharp,使用iTextSharp,如何将多个PDF合并到一个PDF中,而不丢失每个PDF中的表单字段及其属性 (我更喜欢使用数据库流的示例,但文件系统也可以) 我发现这是可行的,但它会使我的PDF变平,所以我不能使用它 更新 @Mark Storer-这是我根据您的反馈(见下文)现在使用的代码,但它在保存后给了我一个损坏的文档。我分别测试了每个代码部分,它在下面显示的MergePdfForms函数中似乎失败了。我显然不想使用示例中的renameFields部分,因为我需要字段名保持“原样” PDF中的字

使用
iTextSharp
,如何将多个PDF合并到一个PDF中,而不丢失每个PDF中的表单字段及其属性

(我更喜欢使用数据库流的示例,但文件系统也可以)

我发现这是可行的,但它会使我的PDF变平,所以我不能使用它

更新

@Mark Storer-这是我根据您的反馈(见下文)现在使用的代码,但它在保存后给了我一个损坏的文档。我分别测试了每个代码部分,它在下面显示的
MergePdfForms
函数中似乎失败了。我显然不想使用示例中的
renameFields
部分,因为我需要字段名保持“原样”


PDF中的字段有一个不寻常的属性:名称相同的所有字段都是相同的字段。他们有共同的价值。当表单引用同一个人,并且表单之间有一个很好的命名方案时,这非常方便。当您想将一个表单的20个实例放入一个PDF中时,它并不方便

至少可以说,这使得合并多个表单具有挑战性。最常见的选择(多亏了iText)是在合并表单之前将表单展平,此时不再合并表单,问题就消失了

另一个选项是在合并字段之前重命名字段。这会使以后的数据提取变得困难,会破坏脚本,通常是PITA。这就是为什么扁平化更受欢迎的原因

iText中有一个名为
PdfCopyFields
的类,它将正确地将字段从一个文档复制到另一个文档。。。它还将正确合并具有相同名称的字段,以便它们真正共享一个值,并且Acrobat/Reader不必在向用户显示文件之前对文件进行大量额外的工作

但是,
PdfCopyFields
不会为您重命名字段。为此,您需要从相关的
PdfReader
获取
AcroFields
对象,并在将文档与
PdfCopyFields
合并之前,在每个字段上调用
renameField(String,String)

所有这些都是基于“AcroForm”的PDF表单。如果您正在处理XFA表单(来自LiveCycle Designer的表单),那么所有的赌注都没有了。你不得不大量使用XML

如果你必须把两者的形式结合起来,上天会帮助你的

因此,如果您正在使用AcroForm字段,那么代码可能是这样的(请原谅我的Java):

公共void合并表单(字符串输出路径,字符串输入路径[]){
PdfCopyFields copier=新的PdfCopyFields(新文件输出流(输出路径));
用于(字符串curInPath:inPath){
PdfReader reader=新PdfReader(curInPath);
重命名字段(reader.getAcroFields());
复印机。添加文件(读卡器);
}
复印机关闭();
}
专用静态整数计数器=0;
私有void重命名字段(AcroFields){
Set fieldNames=fields.getFields().keySet();
String prepend=String.format(“%d.”,计数器++);
for(字符串字段名:字段名){
字段。重命名(字段名,前置+字段名);
}
}
理想情况下,
renameFields
还将创建一个名为prepend's-value的通用字段对象,并将文档中的所有其他字段作为子字段。这将使Acrobat/Reader的生活更加轻松,并避免在关闭Acrobat生成的PDF时出现明显不必要的“保存更改”请求


是的,这就是为什么Acrobat有时会在您不做任何操作时要求您保存更改!Acrobat在幕后做了一些事情。

您也可以使用此代码。。。。它将合并所有pdf文件,而不会丢失字段值

    Document document = new Document();
    try
        {         
           string destinationfile = desktopPath.Replace(@"d:\outputfile.pdf");
           PdfCopyFields copier = new PdfCopyFields(new FileStream(destinationfile,     FileMode.Create));
            PdfImportedPage page;

            //Loops for each file that has been listed
            foreach (string filename in fileList)
            {
                flag++;
                try
                {
                    //The current file path
                    string filePath = sourcefolder + filename;

                    PdfReader reader = new PdfReader(filePath);
                    copier.AddDocument(reader);

                }
                catch
                {

                }
            }
            copier.Close();
        }

好帖子!!希望我能澄清一些问题。是的,它只涉及AcroForms和那些被命名为相同的字段,因为它们应该共享值,并且是相同的字段类型,所以故意被命名为相同的字段。一些相同的命名字段只是X、Y坐标的占位符,其他对象也将标记在这些占位符上。所以,如果我正确理解你的答案,PdfCopyFields听起来会适合我的场景,是吗?似乎不起作用。我根据您的Java示例使用VB.NET代码更新了我的帖子。啊!在保存内存流之前,需要调用
close
。大部分工作都是在这里完成的(就实际写入输出流而言)。如果您的字段看起来像“topmostSubform[0]。Page1[0]。CheckBox[2]”,那么预结束就不起作用了。不是在开头加前缀,而是在结尾加后缀,即
fields.rename(fieldName,fieldName+prepend)。这应该适用于所有情况。@chaitanya除非iText的XFA支持发生了根本性的变化(自从我上次检查以来已经5年多了,所以这当然是可能的),否则简单地重命名字段仍然会在XML中留下各种各样的内容。如果不重命名字段,那么所有共享名称的字段都是同一个字段。这就是AcroForms的工作原理。如果您想要具有相同名称和不同值的可编辑字段,PDF无法帮助您。您可能会在“页面打开”事件中使用JS hackery来完成它,在该事件中,您将根据一些内部数组“手动”将所有字段设置为适当的值。打印可能不起作用,您需要一个自定义提交脚本(您希望使用自己的值集分别提交N个提交,这意味着每次都要构建自己的提交。非常重要。
public void mergeForms(String outpath, String inPaths[]) {
  PdfCopyFields copier = new PdfCopyFields(new FileOutputStream(outpath) );
  for (String curInPath : inPaths) {
    PdfReader reader = new PdfReader(curInPath);
    renameFields(reader.getAcroFields());

    copier.addDocument(reader);
  }
  copier.close();
}

private static int counter = 0;
private void renameFields(AcroFields fields) {
  Set<String> fieldNames = fields.getFields().keySet();
  String prepend = String.format("_%d.", counter++);

  for(String fieldName : fieldNames) {
    fields.rename(fieldName, prepend + fieldName);
  }
}
    Document document = new Document();
    try
        {         
           string destinationfile = desktopPath.Replace(@"d:\outputfile.pdf");
           PdfCopyFields copier = new PdfCopyFields(new FileStream(destinationfile,     FileMode.Create));
            PdfImportedPage page;

            //Loops for each file that has been listed
            foreach (string filename in fileList)
            {
                flag++;
                try
                {
                    //The current file path
                    string filePath = sourcefolder + filename;

                    PdfReader reader = new PdfReader(filePath);
                    copier.AddDocument(reader);

                }
                catch
                {

                }
            }
            copier.Close();
        }