我正在尝试填写模板pdf并在最后添加另一个pdf。 将页面添加到另一个pdf我没有问题,但问题是,当我这样做时,即使我不使用stamper.setFormFlattening(true),我的字段也会丢失。
这是我的代码:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSmartCopy;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
public class ForStack {
public static void main(String[] args) throws IOException, DocumentException, ParseException {
createContractWithMoreFile();
}
public static void createContractWithMoreFile()
throws IOException, DocumentException, ParseException {
String linkPDF = "resources/pdfs/User.pdf";
PdfReader reader = new PdfReader(linkPDF);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos);
PdfWriter writer = stamper.getWriter();
writer.setPdfVersion(PdfWriter.VERSION_1_7);
AcroFields form = stamper.getAcroFields();
form.setField("Name", "Jhon");
stamper.close();
String out = "results/merged.pdf";
List<byte[]> listOfPdfFiles = new ArrayList<>();
listOfPdfFiles.add(baos.toByteArray());
byte[] informativaPrivacy = getPdfByteArray("resources/pdfs/second.pdf");
listOfPdfFiles.add(informativaPrivacy);
concatenatePdfs(listOfPdfFiles, new File(out));
baos.close();
reader.close();
}
public static byte[] getPdfByteArray(String filePath) {
File fileP = new File(filePath);
byte[] result;
try {
result = FileUtils.readFileToByteArray(fileP);
return result;
} catch (IOException e) {
return null;
}
}
public static void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
Document document = new Document();
FileOutputStream outputStream = new FileOutputStream(outputFile);
PdfCopy copy = new PdfSmartCopy(document, outputStream);
document.open();
for (byte[] inFile : listOfPdfFiles) {
PdfReader reader = new PdfReader(inFile);
copy.addDocument(reader);
reader.close();
}
document.close();
}
}
这里是我正在使用的文件
输出文件不是我想要的: result file
那么为什么输出pdf丢失了我的字段?没有连接就没有扁平化......
正如你在我的结果文件中看到的那样,没有字段,所以如果你想再次看到它,我必须使用adobe Acrobat,使用 - &gt;查看(Vista系统) - &GT;工具(Impostazioni) - &GT;创建表单(Prepara Modulo)。 但如果我这样做并尝试退出pdf,Adobe会要求我保存它改变的pdf,而不是我想要的。
我想要的输出pdf在这里: Output File That I want 使用结果文件中丢失的字段
答案 0 :(得分:1)
布鲁诺的回答最初假设来自OP原始代码的stamper.setFormFlattening(true)
来电表示该表格应该被展平。事实证明情况并非如此,这些领域仍然存在。
因此,布鲁诺删除了表格展平线并指出现在的结果是可编辑的,即表格字段存在。但是OP仍然坚持认为他们已经离开了。
事实证明,两者都是正确的,每一个都以他或她自己的方式。区别在于:表单字段在输出中显示为页面上的窗口小部件注释,但 AcroForm 表单定义走了。
要使iText 5.5.x PdfCopy
实例在目标文档中创建 AcroForm 表单定义,其中包含所有复制的源文档的合并表单字段,必须激活其 mergeFields 模式!
如果您想知道为什么默认情况下此模式不活动:它有一个缺点,所有源PdfReader
对象必须保持打开状态,直到目标PdfCopy
实例关闭,这可能导致代码的内存占用量大得多。
要使用 mergeFields 模式,OP的concatenatePdfs
方法
void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
Document document = new Document();
FileOutputStream outputStream = new FileOutputStream(outputFile);
PdfCopy copy = new PdfSmartCopy(document, outputStream);
document.open();
for (byte[] inFile : listOfPdfFiles) {
PdfReader reader = new PdfReader(inFile);
copy.addDocument(reader);
reader.close();
}
document.close();
}
必须像这样重写:
void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
Document document = new Document();
FileOutputStream outputStream = new FileOutputStream(outputFile);
PdfCopy copy = new PdfSmartCopy(document, outputStream);
copy.setMergeFields();
document.open();
List<PdfReader> pdfReaders = new ArrayList<>();
for (byte[] inFile : listOfPdfFiles) {
PdfReader reader = new PdfReader(inFile);
copy.addDocument(reader);
pdfReaders.add(reader);
}
document.close();
pdfReaders.forEach(r -> r.close());
}
(CopyWithField方法concatenatePdfs
)
如您所见, mergeFields 模式由copy.setMergeFields()
激活,而源PdfReader
实例在添加到copy
之后不会立即关闭,而是收集在pdfReaders
中,仅在copy
关闭后关闭(在document.close()
期间隐式关闭)。
答案 1 :(得分:0)
您的代码中存在大量错误。例如:您不需要org.w3c.dom.Document
,您需要com.itextpdf.text.Document
;这个错误导致您的代码甚至无法编译。
我修正了错误,最后得到了这个SSCCE:
package sandbox.merge;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSmartCopy;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
public class ForStack {
public static void main(String[] args) throws IOException, DocumentException, ParseException {
createContractWithMoreFile();
}
public static void createContractWithMoreFile()
throws IOException, DocumentException, ParseException {
String linkPDF = "resources/pdfs/User.pdf";
PdfReader reader = new PdfReader(linkPDF);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos);
PdfWriter writer = stamper.getWriter();
writer.setPdfVersion(PdfWriter.VERSION_1_7);
AcroFields form = stamper.getAcroFields();
form.setField("Name", "Jhon");
stamper.setFormFlattening(true);
stamper.close();
String out = "results/merged.pdf";
List<byte[]> listOfPdfFiles = new ArrayList<>();
listOfPdfFiles.add(baos.toByteArray());
byte[] informativaPrivacy = getPdfByteArray("resources/pdfs/second.pdf");
listOfPdfFiles.add(informativaPrivacy);
concatenatePdfs(listOfPdfFiles, new File(out));
baos.close();
reader.close();
}
public static byte[] getPdfByteArray(String filePath) {
File fileP = new File(filePath);
byte[] result;
try {
result = FileUtils.readFileToByteArray(fileP);
return result;
} catch (IOException e) {
return null;
}
}
public static void concatenatePdfs(List<byte[]> listOfPdfFiles, File outputFile) throws DocumentException, IOException {
Document document = new Document();
FileOutputStream outputStream = new FileOutputStream(outputFile);
PdfCopy copy = new PdfSmartCopy(document, outputStream);
document.open();
for (byte[] inFile : listOfPdfFiles) {
PdfReader reader = new PdfReader(inFile);
copy.addDocument(reader);
reader.close();
}
document.close();
}
}
我只能通过删除以下行来重现您提到的问题:
stamper.setFormFlattening(true);
您的代码中缺少该行,并解释了该表单未展平的原因。
<强>总结强>
当你压扁表格时,你有这个:
曾经是字段"Name"
,我们看到了值"Jhon"
,但字段本身已经消失了:这就是展平:你删除了所有的交互性。
当你没有展平表格时,你有这个:
互动领域仍然存在,没有发现。它填充了值"Jhon"
。
OP似乎想像第一次屏幕截图那样压平表格,同时保持第二次屏幕截图中的字段。这是一个矛盾。如果需要回答,OP应该澄清预期的结果。
iText版本
顺便说一句:我用iText 5.5.13测试了这个。请注意,除非您是付费客户,否则不再支持iText 5。当前版本是iText 7.1.2,但在7.1.2中,PdfStamper
类不再存在。在iText 7中填写表单和合并文档的方式不同。