连接 pdf 而不展平但保留字段
Concatenate pdf without flattening but preserve fields
我正在尝试填写模板 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 ,使用 -> View(Vista)-> Tools(Impostazioni)- > 创建表格 (Prepara Modulo)。
但是如果我这样做并尝试退出 pdf,Adobe 会要求我保存它更改的 pdf,这不是我想要的。
我想要的输出pdf在这里:
Output File That I want
结果文件中丢失的字段
您的代码中有很多错误。比如:你不需要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
class 不再存在。在 iText 7 中填写表单和合并文档的方式有所不同。
Bruno 的回答最初假设来自 OP 原始代码的 stamper.setFormFlattening(true)
调用表明表单应该被展平。事实证明情况并非如此,这些字段应该保留。
因此,Bruno 删除了表单扁平化线并指出结果现在是可编辑的,即存在表单字段。但是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
实例添加到[=20=后不会立即关闭],而是收集在 pdfReaders
中,并且仅在 copy
关闭后关闭(在 document.close()
期间隐式关闭)。
我正在尝试填写模板 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 ,使用 -> View(Vista)-> Tools(Impostazioni)- > 创建表格 (Prepara Modulo)。 但是如果我这样做并尝试退出 pdf,Adobe 会要求我保存它更改的 pdf,这不是我想要的。
我想要的输出pdf在这里:
Output File That I want
结果文件中丢失的字段
您的代码中有很多错误。比如:你不需要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
class 不再存在。在 iText 7 中填写表单和合并文档的方式有所不同。
Bruno 的回答最初假设来自 OP 原始代码的 stamper.setFormFlattening(true)
调用表明表单应该被展平。事实证明情况并非如此,这些字段应该保留。
因此,Bruno 删除了表单扁平化线并指出结果现在是可编辑的,即存在表单字段。但是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
实例添加到[=20=后不会立即关闭],而是收集在 pdfReaders
中,并且仅在 copy
关闭后关闭(在 document.close()
期间隐式关闭)。