iText5.x Настройка внешнего вида кнопки без нарушения печати

Вот контекст:

  1. Мы добавляем две пустые страницы в существующий PDF, каждая из которых содержит пустое поле кнопки
  2. Мы применяем печать PAdES BB со всеми правами на изменение документа
  3. Мы модифицируем кнопку, чтобы вставить в нее изображение

Когда мы пытаемся изменить внешний вид кнопки для установки изображения, срок действия печати нарушается "несанкционированной модификацией" независимо от того, что мы пытаемся сделать.

Вот пример кода:

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();

Мы также попробовали рекомендованным способом в документации без успеха:

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

Проблема в том, что я не знаю, поддерживается ли этот тип модификаций iText или это наш способ изменить кнопку, которая не так?

Обновление:

Если сертификация заменяется простой подписью, мы можем установить внешний вид кнопки, не нарушая ее.

1 ответ

Решение

Почему подпись сертификации нарушена

Ты говоришь

Мы применяем печать PAdES BB со всеми правами на изменение документа

Это не означает, что все мыслимые модификации документа разрешены, но вместо этого разрешены все допустимые изменения. В соответствии со спецификацией PDF возможны следующие варианты:

  1. Изменения в документе не допускаются; любое изменение в документе делает подпись недействительной.
  2. Разрешенные изменения должны заполнять формы, создавать шаблоны страниц и подписываться; другие изменения делают подпись недействительной.
  3. Разрешенные изменения должны быть такими же, как для 2, а также создание, удаление и изменение аннотации; другие изменения делают подпись недействительной.

Таким образом, в случае вашего документа допустимые изменения включают заполнение форм и произвольные манипуляции с аннотациями.

К сожалению, iText 5 при установке "значения" кнопки AcroForm не просто устанавливает вид кнопки на кнопку, а вместо этого

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

Т.е. он по сути заменяет прежнюю кнопку на аналогичную. Это как таковое не допускается.

Почему простая подпись одобрения не сломана

Спецификация PDF не ограничивает изменения, разрешенные для документа, подписанного простой подписью утверждения (если ограничения явно не заданы в преобразовании FieldMDP).

Однажды Adobe утверждала, что они ограничивают изменения, разрешенные для подписанных, но не заверенных документов, например, для заверенных документов со значением ограничения 3 плюс "Добавление полей подписи", ср. это ответ, но, видимо, они немного слабее и в других отношениях. В частности, текущие версии Adobe Reader предупреждают только о "Полях формы с изменениями свойств" в данном случае.

Дополнительное осложнение

У рассматриваемого PDF-файла не только определение формы AcroForm, но и аналогичное определение формы XFA, это документ гибридной формы. Таким образом, чтобы изменить изображение в обоих определениях формы, необходимо учитывать и заполнение формы XFA.

К счастью, способ, которым iText 5 заполняет изображение в форме XFA, не заставляет Adobe Reader считать печать сломанной.

Как установить изображение кнопки вместо того, чтобы не сломать печать

Чтобы не сломать печать, мы должны установить изображение кнопки, не изменяя основную форму, просто виджет. Таким образом, следующий код пытается изменить только внешний вид кнопки:

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();

( SetImageInSignedPdf test testSetInXfaAndAppearanceSampleCert )

В моих тестах это приводит к тому, что изображение становится видимым как в средствах просмотра, которые поддерживают формы XFA, так и в тех, которые этого не делают, а печать не считается нарушенной Adobe Reader.

Осторожно, однако, я только разработал и протестировал это с вашим образцом документа; есть вероятность, что некоторые пограничные условия могут не учитываться.

Другие вопросы по тегам