Настройка поля формы изображения - PullRequest
0 голосов
/ 07 января 2019

Я создал образец PDF-формы с одним полем изображения. Я пытаюсь установить изображение в поле с помощью PDFBox.

Я вижу, что PDFBox рассматривает такое поле как экземпляр PDPushButton, но я не вижу, чтобы интерфейс этого класса предоставлял методы для работы с изображениями ...

Образец PDF можно загрузить с помощью URL-адреса в комментарии.

Как это можно сделать?


EDIT

Вот что я делаю до сих пор:

PDDocument pdfDocument = null;
PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();
if (acroForm != null) {
    PDPushButton field = (PDPushButton) acroForm.getField("test");

    PDImageXObject pdImageXObject = PDImageXObject.createFromFile("my_img.png", pdfDocument);

    List<PDAnnotationWidget> widgets = field.getWidgets();

    /*
     * The field may appear multiple times in the document, I would like to repeat that for every widget (occurence).
     */
    for(PDAnnotationWidget widget : widgets) {
        PDRectangle rectangle = widget.getRectangle();

        //PDAppearanceDictionary appearanceDict = widget.getAppearance();
        /*
         * In my case, when the image is not set with Acrobat DC, appearanceDict is null.
         */

        /*
         * Create the appearance stream and fill it with the image.
         */
        PDAppearanceStream pdAppearanceStream = new PDAppearanceStream(pdfDocument);
        pdAppearanceStream.setResources(new PDResources());
        try (PDPageContentStream pdPageContentStream = new PDPageContentStream(pdfDocument, pdAppearanceStream)) {
            pdPageContentStream.drawImage(pdImageXObject, rectangle.getLowerLeftX(), rectangle.getLowerLeftY(), pdImageXObject.getWidth(), pdImageXObject.getHeight());
        }
        pdAppearanceStream.setBBox(new PDRectangle(rectangle.getWidth(), rectangle.getHeight()));

        /*
         * Create the appearance dict with only one appearance (default) and set the appearance to the widget.
         */
        PDAppearanceDictionary appearanceDict = new PDAppearanceDictionary();
        appearanceDict.setNormalAppearance(pdAppearanceStream);
        widget.setAppearance(appearanceDict);
    }
}

ByteArrayOutputStream outStr = new ByteArrayOutputStream();
pdfDocument.save(outStr);
pdfDocument.close();

Однако сгенерированный PDF не показывает изображение с помощью Acrobat Reader.

Моя цель - начать с этого PDF и использовать PDFBox для получения этого PDF .

Ответы [ 2 ]

0 голосов
/ 10 января 2019

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

Знаете ли вы, что вы можете напрямую добавить изображение в файл PDF? Но если вам нужна подпись, я бы сказал, используйте поле формы подписи. Не злоупотребляйте любыми другими полями. И если вам действительно не нужны функции подписи, сгладьте документ после этого, и изображение останется, но подпись исчезнет. Но многие наши клиенты вначале хотят что-то подобное, но после некоторых вопросов и размышлений они решают использовать настоящие подписи ...

Это то, что вам нужно сделать:

  1. Создание хранилища ключей (лучше всего использовать pkcs12)
  2. Добавить поле подписи в ваш PDF
  3. Подпишите поле (или сделайте это за один шаг с шагом 1)

    KeyStore keystore = KeyStore.getInstance("PKCS12");
    keystore.load(new FileInputStream("YourPathToAKeyStore.p12"), "pw".toCharArray());
    
    File documentFile = new File("YourPdf.pdf");
    CreateVisibleSignature signing = new CreateVisibleSignature(keystore,"pw".toCharArray());
    
    FileInputStream imageStream = new FileInputStream("imageOfTheSignature.png");
    
    signing.setVisibleSignDesigner(-85, imageStream);
    imageStream.close();
    signing.setVisibleSignatureProperties("name", "location", "Security", true);
    signing.setExternalSigning(externalSig);
    
    signing.signPDF(documentFile,new File("signed.pdf"),null,"SignatureField10");
    
  4. <optionally> выровнять документ

0 голосов
/ 08 января 2019

Начнем с того, что стандарт pdf ISO 32000-2 вообще не определяет «поля изображения». Некоторые проприетарные pdf-генераторы / редакторы (в частности, продукты Adobe) используют JavaScript, чтобы поля кнопок работали аналогично полям форм для изображений в графическом интерфейсе, в частности в своих собственных средствах просмотра PDF. Тем не менее эти кнопки являются кнопками, а не полями формы изображения. Таким образом,

PDFBox рассматривает такое поле как экземпляр PDPushButton, но я не вижу, чтобы интерфейс этого класса предоставлял методы для работы с изображениями ...

Если вам действительно нужно что-то вроде поля изображения, тем не менее, нет необходимости искать другое решение для эмуляции полей изображения, можно просто последовать примеру Adobe. Нужно просто знать, что только эмулирует полей изображения.

Чтобы заполнить поле кнопки изображением, можно использовать AcroFormPopulator Ренат Гатин представляет в свой ответ на свой вопрос "Как вставить изображение программно в поле AcroForm, используя java PDFBox? ".

Осторожно, однако, применительно к вашему файлу с примерами обнаруживается ошибка в коде выравнивания формы PDFBox. Таким образом, вы должны деактивировать сплющивание формы в AcroFormPopulator, т.е. удалить в нем acroForm.flatten().

Данная ошибка связана с отсутствующим преобразованием: если XObject используется как внешний вид поля формы, все в его ограничительной рамке по спецификации автоматически перемещается в прямоугольник аннотации:

1. Ограничительная рамка внешнего вида (указанная в ее записи BBox ) должна быть преобразована с использованием Matrix , чтобы получить четырехугольник с произвольной ориентацией. Преобразованная коробка внешнего вида - это наименьший вертикальный прямоугольник, охватывающий этот четырехугольник.

2. Должна быть рассчитана матрица A , которая масштабирует и преобразует преобразованную рамку внешнего вида в соответствие с краями прямоугольника аннотации (указанной в записи Rect ). A отображает левый нижний угол (угол с наименьшими x и y координатами) и верхний правый угол (угол с наибольшим x и y координаты) преобразованного окна внешнего вида в соответствующие углы прямоугольника аннотации.

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

(ISO 32000-2, раздел 12.5.5 Потоки внешнего вида, Алгоритм: потоки внешнего вида)

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

Видимо, выравнивание формы PDFBox, по крайней мере, не создает эту матрицу AA , в частности, предполагается, что ограничивающий прямоугольник внизу слева всегда будет в начале координатной системы.

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

PS: Ситуация даже более странная, чем ожидалось, PDAcroForm.flatten(List<PDField>, boolean) пытается определить, необходим ли перевод или масштабирование прежнего внешнего вида XObject, и добавляет преобразование, если считает, что это необходимо, но

1. при проверке необходимости перевода в PDAcroForm.resolveNeedsTranslation(PDAppearanceStream) он фактически проверяет ресурсы формы XObject внешнего вида XObject; в том и только в том случае, если среди них есть объект XObject с ограничительной рамкой, в которой ни одна из опорных координат не равна 0, предполагается, что перевод не требуется. - Это очень странный тест, правильный тест должен был бы проверить ограничивающий прямоугольник самого XObject внешнего вида, а не формы XObject, которые он содержит. В примере документа внешний вид XObject не содержит никаких форм XObject, поэтому автоматически предполагается, что требуется перевод.

2. при добавлении трансляционного преобразования он снова игнорирует ограничивающий прямоугольник внешнего вида XObject и переводит, как если бы якорь внешнего вида XObject находился в начале координат системы координат. - В образце документа это совершенно неадекватно, так как якорь ограничивающего прямоугольника уже расположен так далеко, что приводит к его перемещению в два раза на требуемое расстояние от источника.

3. при проверке необходимости перевода в PDAcroForm.resolveNeedsScaling(PDAppearanceStream) он фактически проверяет наличие произвольных XObject-ов и предполагает, что при наличии такого XObject-а требуется масштабирование. - В примере документа есть изображение XObject, поэтому предполагается, что масштабирование необходимо ... странно.

Эти 3 детали не имеют никакого смысла вообще. (Ну, возможно, были некоторые образцы документов, для которых они случайно дали желаемый результат, но в целом это чепуха.)

...