itext7 PdfButtonFormField setImage方法不适用于签名的pdf

时间:2018-10-31 12:07:46

标签: itext7

我正在使用如下所示的itext7 Java库将PdfButtonFormField添加到现有的pdf中:

String src = "sample.pdf";
String dest = "acro_sample_empty_fields.pdf";


PdfDocument pdf = new PdfDocument(new PdfReader(src), new     PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
PdfButtonFormField button = PdfFormField.createPushButton(pdf, new Rectangle(Integer.parseInt(control.xCord), Integer.parseInt(control.yCord),Integer.parseInt(control.width), Integer.parseInt(control.height)), control.name, control.value);

form.addField(button, page);

String resource = "sample.png";
button.setImage(resource);

此后,我使用以下代码填写如下表格:

String src = "1540982441_313554925_acro_sample_empty_fields_signedFinal.pdf";
String dest = "acro_sample_filled_fields.pdf";

PdfReader reader = new PdfReader(src);
File output = new File(dest);

OutputStream outputStream = new FileOutputStream(output);
PdfDocument document = new PdfDocument(reader,
                    new PdfWriter(outputStream),
                    new StampingProperties().useAppendMode());
PdfAcroForm form = PdfAcroForm.getAcroForm(document, true);
Map<String, PdfFormField> fields = form.getFormFields();

String resource = "sample_test.png";
((PdfButtonFormField)fields.get(control.name)).setImage(resource);

对于正常的pdf,一切正常。但是,如果我对创建的pdf进行数字签名,然后尝试填充它。则图像设置不正确。 对于普通pdf,按钮上的图像已按预期更改。但是在经过数字签名的pdf上,图像未设置。

我已经尝试过在Google上寻找此商品,但还没有运气。任何帮助将不胜感激。预先感谢。

1 个答案:

答案 0 :(得分:0)

我使用the signed but unfilled PDF you shared测试了此答案中的代码。但是,由于您没有共享示例图像,因此我使用了自己的图像。

更精确的观察

你说

  

对于正常的pdf,一切正常。但是,如果我对创建的pdf进行数字签名,然后尝试填充它。则图像设置不正确。对于普通pdf,按钮上的图像已按预期更改。但是在经过数字签名的pdf上,图像未设置。

这并非完全正确,图像已设置为 ,但并非所有PDF查看器都显示

详细信息:如果使用代码在签名的PDF中设置图像,则Adobe Reader实际上仅显示一个灰色框

Adobe Reader Screen shot

,但其他PDF查看器,例如福昕浏览器或Chrome的内置查看器会显示替换图片

Foxit screen shot

因此,图像也被设置为经过数字签名的PDF。实际的问题是Adobe Reader无法显示它!

原因

经过分析并发现一些红色鲱鱼后,出现问题的原因似乎是如果Adobe Reader显示PDF时AcroForm按钮外观已更改,并且

  • 未对PDF进行签名,那么Adobe Reader仅使用更新的外观流;但是如果
  • 对PDF进行签名,然后Adobe Reader尝试忽略更新的外观流,并根据外观特征信息构造新的外观。

(不过,其他PDF查看器似乎总是使用更新的外观流。)

iText确实为按钮创建了外观特征字典(因此Adobe Reader假定它可以忽略更新的外观,并可以基于此字典构造一个新的外观),但不幸的是,在构造时,它们都没有向按钮添加一些特定于按钮的信息。按钮或更改按钮时。这尤其涉及以下两个条目:

  

  流   (可选;仅按钮字段;应为间接引用)定义小部件注释的常规图标的表格XObject,当其不与用户交互时,将显示该图标。

     

TP   整数   (可选;仅按钮字段)一个代码,指示小部件注释的标题的文本相对于其图标的位置:

     

0 没有图标;仅标题

     

1 无标题;仅限图标

     图标下方的

2 标题

     图标上方的

3 标题

     图标右侧的

4 标题

     图标左侧的

5 标题

     

6 字幕直接覆盖在图标上

     

默认值: 0

(ISO 32000-2,表192-外观特征字典中的条目)

由于iText不提供 TP 值,因此会出现默认值,并且Adobe Reader创建带有“无图标;仅标题”的按钮外观。由于未定义标题,因此结果是一个灰色框。

解决方法

最简单的解决方法是在图像更新过程中删除整个外观特征字典,即替换

((PdfButtonFormField)fields.get(control.name)).setImage(resource);

作者

PdfButtonFormField button = (PdfButtonFormField)fields.get(control.name);
button.setImage(resource);
if (button.getPdfObject().containsKey(PdfName.MK)) {
    button.setModified();
    button.getPdfObject().remove(PdfName.MK);
}

SetButtonImage辅助方法setLikeGautamAnandImproved

现在Adobe Reader找不到任何外观特征,因此不能忽略更新的外观流。

修复

或者,我们可以添加缺少的外观特征条目,例如像这样:

PdfButtonFormField button = (PdfButtonFormField)fields.get(control.name);
button.setImage(resource);
PdfWidgetAnnotation widget = button.getWidgets().get(0);
PdfDictionary characteristics = widget.getAppearanceCharacteristics();
if (characteristics != null) {
    characteristics.setModified();
    characteristics.put(PdfName.I, widget.getNormalAppearanceObject());
    characteristics.put(PdfName.TP, new PdfNumber(1));
}

SetButtonImage辅助方法setLikeGautamAnandImproved2

结果看上去略有不同,

Adobe Reader Screen shot

如您所见,图像周围有一个小框。相应地设置其他特征,很可能会使它消失。