我正在使用此表格https://help.adobe.com/en_us/acrobat/9.0/samples/samples/interactiveform_enabled.pdf
被称为So:
Pdf.editForm("./src/main/resources/pdfs/interactiveform_enabled.pdf", "./src/main/resources/pdfs/FILLEDOUT.pdf"));
其中Pdf
只是一个工人类,editForm
是静态方法。
editForm
方法看起来像这样:
public static int editForm(String inputPath, String outputPath) {
try {
PdfDocument pdf = new PdfDocument(new PdfReader(inputPath), new PdfWriter(outputPath));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
Map<String, PdfFormField> m = form.getFormFields();
for (String s : m.keySet()) {
if (s.equals("Name_First")) {
m.get(s).setValue("Tristan");
}
if (s.equals("BACHELORS DEGREE")) {
m.get(s).setValue("Off"); // On or Off
}
if (s.equals("Sex")) {
m.get(s).setValue("FEMALE");
}
System.out.println(s);
}
pdf.close();
logger.info("Completed");
} catch (IOException e) {
logger.error("Unable to fill form " + outputPath + "nt" + e);
return 1;
}
return 0;
}
不幸的是,填充文件在调用此方法后不再是表格。我做错了吗?
我正在使用此资源进行指导。请注意我如何不打电话给form.flattenFields()
。但是,如果我称之为该方法,我会发现java.lang.IllegalArgumentException
的错误。
谢谢您的时间。
您的表格是启用读者的,即它包含用钥匙和Adobe发行的证书向常规Adobe读者表示的用法权利数字签名,它将激活许多其他功能在那个非常pdf上操作时
如果您像原始代码中标记文件,则现有的PDF对象将被重新排列并稍微更改。这打破了使用权签名,Adobe Reader认识到,否认"自创建以来已更改了该文档,并且不再使用扩展功能。"
但是,如果将文件盖在附加模式中,则将更改附加到PDF作为增量更新。因此,签名仍然正确地签名其原始字节范围,而Adobe读取器不抱怨。
激活附加模式,创建PdfDocument
时使用StampingProperties
:
PdfDocument pdf = new PdfDocument(new PdfReader(inputPath), new PdfWriter(outputPath), new StampingProperties().useAppendMode());
(使用ITEXT 7.1.1-SNAPSHOT和ADOBE ACROBAT读取器DC版本2018.009.20050进行测试)
顺便说一句,Adobe读取器不仅检查签名,还试图确定增量更新中的更改是否不超出使用使用权签名激活的附加功能的范围。
否则,您可以简单地采用一个启用读者的小型PDF,然后在附加模式下,将所有现有页面替换为自己选择的内容。当然,这不符合Adobe的利益...
填充的PDF仍然是ACROFOR,否则以下示例将导致两次相同的PDF。
public class Main {
public static final String SRC = "src/main/resources/interactiveform_enabled.pdf";
public static final String DEST = "results/filled_form.pdf";
public static final String DEST2 = "results/filled_form_second_time.pdf";
public static void main(String[] args) throws Exception {
File file = new File(DEST);
file.getParentFile().mkdirs();
Main main = new Main();
Map<String, String> data1 = new HashMap<>();
data1.put("Name_First", "Tristan");
data1.put("BACHELORS DEGREE", "Off");
main.fillPdf(SRC, DEST, data1, false);
Map<String, String> data2 = new HashMap<>();
data2.put("Sex", "FEMALE");
main.fillPdf(DEST, DEST2, data2, false);
}
private void fillPdf(String src, String dest, Map<String, String> data, boolean flatten) {
try {
PdfDocument pdf = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
//Delete print field from acroform because it is defined in the contentstream not in the formfields
form.removeField("Print");
Map<String, PdfFormField> m = form.getFormFields();
for (String d : data.keySet()) {
for (String s : m.keySet()) {
if(s.equals(d)){
m.get(s).setValue(data.get(d));
}
}
}
if(flatten){
form.flattenFields();
}
pdf.close();
System.out.println("Completed");
} catch (IOException e) {
System.out.println("Unable to fill form " + dest + "nt" + e);
}
}
}
您面临的问题与"启用读者的表单"有关。它归结为最初馈送给程序的PDF文件启用了读者。因此,您可以在Adobe Reader中打开PDF并填写表格。这使Acrobat用户可以扩展Adobe读取器的行为。使用ITEXT填充PDF并关闭后,它将PDF保存为"不读取器延伸"。这使得仍然可以使用Itext填充Actroform,但是当您使用Adobe读取器打开PDF时,您在原始PDF中看到的扩展功能已消失。但这并不意味着表格被扁平。
itext无法使启用读取器启用,事实上,创建启用阅读器的表单的唯一方法是使用Acrobat Professional。这就是Acrobat和Adobe Reader交互的方式,它不是Itext可以模仿或解决的方法。您可以在此链接上找到更多信息和可能的解决方案。
调用form.flattenfields()方法时,您会获得的niLegalArgumentException是因为PDF文档的构造方式。"打印形式"按钮应该在AcroForm中定义,但是在PDF的ContentStream中定义了它,这意味着Acroform中的按钮具有空的文本值,这就是导致例外的原因。
。您可以通过在变平之前从Acroform中删除打印字段来解决此问题。
illegalargumentException问题已在ITEXT 7.1.5中固定。