iText5.x设置按钮外观而不会破坏密封 [英] iText5.x Setting pushbutton appearance without breaking Seal

查看:105
本文介绍了iText5.x设置按钮外观而不会破坏密封的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里是上下文:

  1. 我们将两个空白页面添加到现有的pdf中,每个页面包含一个空白按钮字段
  2. 我们对文件使用PAdES B-B印章,并拥有所有修改权利
  3. 我们修改按钮以在其中插入图像

当我们尝试修改按钮外观以设置图像时,无论尝试如何,印章有效性都会因未经授权的修改"而中断.

When we try to modify the pushbutton appearance to set an image, the seal validity breaks with "unauthorized modification" no matter what we try.

这是一个代码示例:

PdfReader pdfReader = new PdfReader("test.pdf");
PdfStamper pdfStamper = new PdfStamper(pdfReader, output, pdfReader.getPdfVersion(), true);

AcroFields acroFields = pdfStamper.getAcroFields();
String imageFieldId = "imageField1";
acroFields.setField(imageFieldId, Base64.encodeBytes(consentImage));

pdfStamper.close();
pdfReader.close();

我们还尝试了文档中推荐的方法,但没有成功:

We also tried with the recommanded way in documentation without success:

PushbuttonField pbField = acroFields.getNewPushbuttonFromField(imageFieldId);
pbField.setImage(Image.getInstance("image1.jpg"));
acroFields.replacePushbuttonField(imageFieldId, pbField.getField());

问题是:我不知道iText是否支持这种类型的修改,或者这是我们修改按钮的方式吗?

Problem is: i don't know if that type of modification is supported by iText or if it's our way of modifying the button which is wrong?

更新:

如果将证书替换为简单的签名,我们可以设置按钮外观而不会损坏按钮.

If the certification is replaced by a simple signature, we can set the pushbutton appearance without breaking it.

推荐答案

为什么证书签名已损坏

你说

我们对文件使用PAdES B-B印章,并拥有所有修改权利

We apply a PAdES B-B seal with all modification rights on the document

并不表示允许对文档进行所有可能的修改,而是允许对所有可能进行的修改.根据PDF规范,选择为:

which does not mean that all imaginable modifications of the document are allowed but instead that all allowable modifications are allowed. According to the PDF specification the choices are:

  1. 不允许对文档进行任何更改;对文档的任何更改都将使签名无效.
  2. 允许的更改应填写表格,实例化页面模板并签名;其他更改将使签名无效.
  3. 允许的更改应与第2项相同,以及注释的创建,删除和修改;其他更改将使签名无效.

因此,对于您的文档,允许的更改包括表单填写和任意注释操作.

Thus, in case of your document the allowed changes include form fill-ins and arbitrary annotation manipulation.

很遗憾,iText 5设置为值"时, AcroForm按钮的功能,不仅将按钮外观设置为按钮,而且

Unfortunately iText 5, when setting "the value" of an AcroForm push button, does not merely set the button appearance to the button but instead

PushbuttonField pb = getNewPushbuttonFromField(name);
pb.setImage(img);
replacePushbuttonField(name, pb.getField());

即它实际上是用类似的按钮替换以前的按钮.这样是不允许的.

I.e. it essentially replaces the former push button with a similar one. This as such is not allowed.

PDF规范并不将允许的更改限制为仅由批准签名签署的文档(除非在FieldMDP转换中明确给出了限制).

The PDF specification does not restrict the changes allowed to a document signed by a mere approval signature (unless restrictions explicitly are given in a FieldMDP transform).

Adob​​e曾经声称他们确实将允许对已签名但未经认证的文档的更改限制为限制值3加添加签名字段"的经认证的文档,例如cf. 此答案,但显然它们在其他方面也有点松懈.特别地,当前的Adobe Reader版本仅警告具有属性更改的表单域".在眼前的情况下.

Adobe once claimed that they do restrict changes allowed to signed but not certified documents like those to a certified document with restriction value 3 plus "Adding signature fields", cf. this answer, but apparently they are a bit laxer in other respects, too. In particular current Adobe Reader versions only warn about "Form Fields with Property Changes" in the case at hand.

所讨论的PDF实际上并不仅仅具有AcroForm表单定义,而是具有类似的XFA表单定义,它是一个混合表单文档.因此,要更改两个表单定义中的图像,还必须考虑XFA表单的填写.

The PDF in question actually does not have only the AcroForm form definition, instead it has a similar XFA form definition, it is a hybrid form document. Thus, to change the image in both form definitions, one has to consider the filling of the XFA form, too.

幸运的是,iText 5将图像填充到XFA表单中的方式并不能使Adobe Reader认为封印已损坏.

Fortunately, the way iText 5 fills in the image into the XFA form does not make Adobe Reader assume the seal broken.

为了不破坏印章,我们必须设置按钮图像而不更改底层形式,仅更改小部件即可.因此,以下代码试图仅更改按钮的外观:

To not break the seal, we have to set the button image without changing the underlying form, merely the widget. Thus, the following code attempts to only change the appearance of the button:

PdfReader pdfReader = new PdfReader(SOURCE);
PdfStamper pdfStamper = new PdfStamper(pdfReader, TARGET, pdfReader.getPdfVersion(), true);
byte[] bytes = IMAGE_BYTES;

AcroFields acroFields = pdfStamper.getAcroFields();
String name = "mainform[0].subform_0[0].image_0_0[0]";
String value = Base64.getEncoder().encodeToString(bytes);
Image image = Image.getInstance(bytes);

XfaForm xfa = acroFields.getXfa();
if (xfa.isXfaPresent()) {
    name = xfa.findFieldName(name, acroFields);
    if (name != null) {
        String shortName = XfaForm.Xml2Som.getShortName(name);
        Node xn = xfa.findDatasetsNode(shortName);
        if (xn == null) {
            xn = xfa.getDatasetsSom().insertNode(xfa.getDatasetsNode(), shortName);
        }
        xfa.setNodeText(xn, value);
    }
}

PdfDictionary widget = acroFields.getFieldItem(name).getWidget(0);
PdfArray boxArray = widget.getAsArray(PdfName.RECT);
Rectangle box = new Rectangle(boxArray.getAsNumber(0).floatValue(), boxArray.getAsNumber(1).floatValue(), boxArray.getAsNumber(2).floatValue(), boxArray.getAsNumber(3).floatValue());

float ratioImage = image.getWidth() / image.getHeight();
float ratioBox = box.getWidth() / box.getHeight();
boolean fillHorizontally = ratioImage > ratioBox;
float width = fillHorizontally ? 1 : ratioBox / ratioImage;
float height = fillHorizontally ? ratioImage / ratioBox : 1;
float xOffset = 0; // centered: (width - 1) / 2;
float yOffset = height - 1; // centered: (height - 1) / 2;
PdfAppearance app = PdfAppearance.createAppearance(pdfStamper.getWriter(), width, height);
app.addImage(image, 1, 0, 0, 1, xOffset, yOffset);
PdfDictionary dic = (PdfDictionary)widget.get(PdfName.AP);
if (dic == null)
    dic = new PdfDictionary();
dic.put(PdfAnnotation.APPEARANCE_NORMAL, app.getIndirectReference());
widget.put(PdfName.AP, dic);
pdfStamper.markUsed(widget);

pdfStamper.close();
pdfReader.close();

(在我的测试中,这导致图像在支持XFA表单的查看器和不支持XFA表单的查看器中均可见,并且Adobe Reader不认为该印章已损坏.

In my tests this results in the image being visible both in viewers that support XFA forms and those that don't, and the seal not being considered broken by Adobe Reader.

但是,请注意,我仅使用您的示例文档进行了开发和测试;有可能不考虑某些边境条件.

Beware, though, I only developed and tested this with your sample document; chances are that some border conditions might not be considered.

这篇关于iText5.x设置按钮外观而不会破坏密封的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆