Java iText填写表格/将页面复制到新文档

Java iText填写表格/将页面复制到新文档,java,pdf,itext7,Java,Pdf,Itext7,我正在使用iText填充一个包含AcroForm的PDF模板。 现在,我想用这个模板创建一个新的PDF页面。 我的想法是填充模板PDF,用写入的字段复制页面,并将其添加到新文件中。他们的主要问题是,我们的客户希望自己设计模板。所以我不确定我是否尝试了正确的方法来解决这个问题 因此,我创建了这段代码,但现在无法工作。我得到了错误com.itextpdf.io.IOException:PDF头未找到。 我的代码 x = 1; try (PdfDocument finalDoc = new PdfD

我正在使用
iText
填充一个包含
AcroForm
的PDF模板。 现在,我想用这个模板创建一个新的PDF页面。 我的想法是填充模板PDF,用写入的字段复制页面,并将其添加到新文件中。他们的主要问题是,我们的客户希望自己设计模板。所以我不确定我是否尝试了正确的方法来解决这个问题

因此,我创建了这段代码,但现在无法工作。我得到了错误
com.itextpdf.io.IOException:PDF头未找到。

我的代码

 x = 1;
try (PdfDocument finalDoc = new PdfDocument(new PdfWriter("C:\\Users\\...Final.pdf"))) {
        for (HashMap<String, String> map : testValues) {
            String path1 = "C:\\Users\\.....Temp.pdf"
            InputStream template = templateValues.get("Template");

            PdfWriter writer = new PdfWriter(path1);

            try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(template), writer)) {
                PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
                for (HashMap.Entry<String, String> map2 : map.entrySet()) {

                    if (form.getField(map2.getKey()) != null) {
                        Map<String, PdfFormField> fields = form.getFormFields();
                        fields.get(map2.getKey()).setValue(map2.getValue());


                    }

                }
            } catch (IOException | PdfException ex) {
                System.err.println("Ex2: " + ex.getMessage());

            }
            if (x != 0 && (x % 5) == 0) {
                try (PdfDocument tempDoc = new PdfDocument(new PdfReader(path1))) {
                    PdfPage page = tempDoc.getFirstPage();
                    finalDoc.addPage(page.copyTo(finalDoc));

                } catch (IOException | PdfException ex) {
                    System.err.println("Ex3: " + ex.getMessage());

                }

            }
             x++;
       }
    } catch (IOException | PdfException ex) {
        System.err.println("Ex: " + ex.getMessage());
    }
x=1;
try(PdfDocument finalDoc=新的PdfDocument(新的PdfWriter(“C:\\Users\\\…Final.pdf”)){
for(HashMap映射:testValues){
String path1=“C:\\Users\\..…Temp.pdf”
InputStream template=templateValues.get(“模板”);
PdfWriter writer=新的PdfWriter(路径1);
try(PdfDocument pdfDoc=newpdfdocument(newpdfreader(模板)、writer)){
PdfAcroForm form=PdfAcroForm.getAcroForm(pdfDoc,true);
对于(HashMap.Entry map2:map.entrySet()){
if(form.getField(map2.getKey())!=null){
映射字段=form.getFormFields();
fields.get(map2.getKey()).setValue(map2.getValue());
}
}
}捕获(IOException | PDFEException ex){
System.err.println(“Ex2:+ex.getMessage());
}
如果(x!=0&(x%5)==0){
try(PdfDocument tempDoc=newpdfdocument(newpdfreader(path1))){
PdfPage page=tempDoc.getFirstPage();
finalDoc.addPage(page.copyTo(finalDoc));
}捕获(IOException | PDFEException ex){
System.err.println(“Ex3:+ex.getMessage());
}
}
x++;
}
}捕获(IOException | PDFEException ex){
System.err.println(“Ex:+Ex.getMessage());
}

完成向PDF文档添加内容后关闭它们。

完成向PDF文档添加内容后关闭它们。

第1部分-PDF标题缺失 这似乎是由于您试图在已读取的循环中重新读取InputStream/而导致的(并且,根据PdfReader的配置,该循环已关闭)。解决这一问题取决于所使用的InputStream的具体类型-如果您想将其保留为简单的InputStream(与更具体但更具能力的InputStream类型相比),则需要首先将字节从流中提取到内存中(例如ByteArrayOutputStream),然后基于这些字节创建PDF阅读器

i、 e

第2部分-其他问题 两件事

  • 确保获取最近发布的7.0.1版本的iText,因为它包含了两个修复wrt/AcroForm处理
  • 您可能可以在临时PDF中使用ByteArrayOutputStreams(而不是将它们写入文件),我将在下面的示例中使用这种方法
  • PdfDocument/PdfPage在“内核”模块中,而AcroForms在“表单”模块中(这意味着PdfPage故意不知道AcroForms)——IPdfPageExtraCopier是模块之间的桥梁。为了正确复制AcroForms,您需要使用两个arg copyTo()版本,并传递一个PdfPageFormCopier实例
  • 字段名在文档中必须是唯一的(即“绝对”字段名-我现在跳过字段层次结构)。由于我们多次循环并添加模板中的字段,我们需要想出一个策略来重命名字段以确保唯一性(当前的API在这方面实际上有点笨拙)

    File acroFormTemplate=新文件(“someTemplate.pdf”);
    Map someMapOfFieldToValues=新HashMap();
    试一试(
    PdfDocument finalOutput=新的PdfDocument(新的PdfWriter(新的FileOutputStream)(新文件(“finalOutput.pdf”));
    ) {
    对于(/*某些循环条件*/int x=0;x<5;x++){
    //对于循环的每个迭代,在内存中创建一个临时
    //PDF来处理表单字段编辑。
    ByteArrayOutputStream tmp=新的ByteArrayOutputStream();
    试一试(
    PdfDocument filledAcroFormTemplate=新PdfDocument(新PDF阅读器(新文件输入流(acroFormTemplate)),新PDF编写器(tmp));
    ) {
    PdfAcroForm acroForm=PdfAcroForm.getAcroForm(filledInAcroFormTemplate,true);
    对于(PdfFormField字段:acroForm.getFormFields().values()){
    if(someMapOfFieldToValues.containsKey(field.getFieldName())){
    setValue(someMapOfFieldToValues.get(field.getFieldName());
    }
    }
    //请注意,因为我们多次添加模板
    //我们需要采取字段重命名策略,以确保字段
    //最终文件中的唯一性。为了演示起见
    //我们只需将它们重命名为前缀w/我们的循环计数器
    List fieldNames=new ArrayList();
    fieldNames.addAll(acroForm.getFormFields().keySet());//避免混淆修改
    for(字符串字段名:字段名){
    acroForm.renameField(字段名,x+“”+字段名);
    }
    }
    //对于所有PDF定稿,临时PDF需要“关闭”
    //神奇的事情发生了…所以打开新的只读版本作为
    //来自内存中bucket-o-bytes的合并源
    试一试(
    PdfDocument readOnlyFilledInAcroFormTemplate=新的PdfDocument(新的PdfReader(新的ByteArrayInputStream(tmp.toByteArray()));
    ) {
    //虽然PdfPage.copyTo可能适用于简单页面,但PdfDocument.copyPagesTo
    //是更全面的副本(更广泛地支持复制大纲和标记内容)
    
    ByteArrayOutputStream templateBuffer = new ByteArrayOutputStream();
    while ((int c = template.read()) > 0) templateBuffer.write(c);
    for (/* your loop */) {
        ...
        PdfDocument filledInAcroFormTemplate = new PdfDocument(new PdfReader(new ByteArrayInputStream(templateBuffer.toByteArray())), new PdfWriter(tmp))
       ...
    
    File acroFormTemplate = new File("someTemplate.pdf");
    Map<String, String> someMapOfFieldToValues = new HashMap<>();
    try (
        PdfDocument  finalOutput = new PdfDocument(new PdfWriter(new FileOutputStream(new File("finalOutput.pdf")));
    ) {
        for (/* some looping condition */int x = 0; x < 5; x++) {
            // for each iteration of the loop, create a temporary in-memory
            // PDF to handle form field edits.
            ByteArrayOutputStream tmp = new ByteArrayOutputStream();
            try (
                PdfDocument filledInAcroFormTemplate = new PdfDocument(new PdfReader(new FileInputStream(acroFormTemplate)), new PdfWriter(tmp));
            ) {
                PdfAcroForm acroForm = PdfAcroForm.getAcroForm(filledInAcroFormTemplate, true);
                for (PdfFormField field : acroForm.getFormFields().values()) {
                    if (someMapOfFieldToValues.containsKey(field.getFieldName())) {
                        field.setValue(someMapOfFieldToValues.get(field.getFieldName()));
                    }
                }
                // NOTE that because we're adding the template multiple times
                // we need to adopt a field renaming strategy to ensure field
                // uniqueness in the final document.  For demonstration's sake
                // we'll just rename them prefixed w/ our loop counter
                List<String> fieldNames = new ArrayList<>();
                fieldNames.addAll(acroForm.getFormFields().keySet()); // avoid ConfurrentModification
                for (String fieldName : fieldNames) {
                    acroForm.renameField(fieldName, x+"_"+fieldName);
                }
            }
    
            // the temp PDF needs to be "closed" for all the PDF finalization
            // magic to happen...so open up new read-only version to act as
            // the source for the merging from our in-memory bucket-o-bytes
            try (
                PdfDocument readOnlyFilledInAcroFormTemplate = new PdfDocument(new PdfReader(new ByteArrayInputStream(tmp.toByteArray())));
            ) {
                // although PdfPage.copyTo will probably work for simple pages, PdfDocument.copyPagesTo
                // is a more comprehensive copy (wider support for copying Outlines and Tagged content)
                // so it's more suitable for general page-copy use.  Also, since we're copying AcroForm
                // content, we need to use the PdfPageFormCopier
                readOnlyFilledInAcroFormTemplate.copyPagesTo(1, 1, finalOutput, new PdfPageFormCopier());
            }
        }
    }