Как прикрепить подписи к PDF с помощью iText? - PullRequest
0 голосов
/ 18 июня 2019

Я имею в реализации, которая работает для простых случаев, но не для сложных случаев.Исходный PDF-файл отображается в центральной панели. У меня есть боковая панель, в которой есть несколько прямоугольников, таких как «Имя», «Подпись», «Отметка времени», которые можно перетаскивать на PDF-файл.Используя jQuery draggable & droppable, я могу получить координаты точек отбрасывания и сохранить их в базе данных.Используя PdfStamper iText, я получаю PdfContentByte и добавляю к нему изображение подписи.Это работает, если PDF-документ является однородным - скажем, все страницы имеют размер письма.Но не удается в тех случаях, когда страницы представляют собой смесь ландшафта и портрета.Подпись вставляется в правильном месте для альбомных страниц, но не в надлежащем месте для портретных страниц.Если все страницы в альбомной ориентации, то проблем нет.Точно так же, если все страницы являются портретными, то также не проблема.

Я понимаю, что изображения измеряются в пикселях, тогда как размеры PDF указаны в точках.Поэтому я преобразовал координаты изображения в пикселях в точку (0,75).Также принимается во внимание, что для изображений начало координат находится в верхнем левом
углу, тогда как в pdf начало координат находится в нижнем левом углу, для оси изображения y - юг, а для оси y pdf - север.

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

Редактировать:

Вот код: DocumentField это POJO, который имеет свойства для подписикоординаты

public void writeDocumentFields(List<DocumentField> documentField,File file, File outputFile) throws IOException    {
    try {
        PdfReader pdfReader = new PdfReader(file.getAbsolutePath());
        PdfReader.unethicalreading=true;
        PdfStamper pdfStamper = new PdfStamper(pdfReader,new FileOutputStream(outputFile));
        for(DocumentField df:documentField){
            int pageNumber = df.getPageNumber()+1;
            PdfContentByte content = pdfStamper.getOverContent(pageNumber);
            Rectangle cropBox = pdfReader.getCropBox(pageNumber);
            if(pdfReader.getPageRotation(pageNumber) > 0) {
                float width = cropBox.getRight();
                cropBox.setRight(cropBox.getHeight());
                cropBox.setTop(width);                   
            }

            if(df.getFieldType().equals("image")){
                df.setxPosition(
                    Float.parseFloat(df.getLeft())*
                    CONVERSION_FACTOR_FROM_PIXEL_TO_POINT);
                df.setyPosition(Float.parseFloat(df.getTop())*CONVERSION_FACTOR_FROM_PIXEL_TO_POINT);
                float x = cropBox.getLeft()  + df.getxPosition();
                float y = cropBox.getTop()  - df.getyPosition();
                Image image = Image.getInstance(df.getFieldValue());
                image.scaleToFit(150*CONVERSION_FACTOR_FROM_PIXEL_TO_POINT, 50*CONVERSION_FACTOR_FROM_PIXEL_TO_POINT);
                image.setAbsolutePosition(x, y - 36f);
                content.addImage(image);
            }else if(df.getFieldType().equals("checkbox")){
                //...
            }else{
                //...
            }
        }
        pdfStamper.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (DocumentException e) {
        e.printStackTrace();
    }
}   

PDF с альбомной ориентацией и портретом, я всегда подписываюсь в одном и том же месте

Другой пример, смешанный pdf

2-е редактирование

Этот 2-й пример PDF имеет 3 страницы, размеры для 1-й страницы 682,04 x 297,12, 2-я страница 610,52 x 788,6, 3-я страница почти такая же, как 2-я страница611 х 789,08.Сначала я попытался разместить подпись в верхнем левом углу каждой страницы. Это удалось.Затем я попытался разместить подпись в левом нижнем углу каждой страницы. Это не удалось. Я сохраняю координаты изображения, перетаскиваемого в базу данных, и значения (0, 350,484), (0,352,328) и (7,301,688).Координата x 3-го значения должна была быть 0, мы можем игнорировать это небольшое отклонение.Теперь на 1-й странице подпись встраивается в нужном месте.Но для 2-й и 3-й страницы они являются почти серединой страницы в направлении y, x в порядке, т. Е. 0. координаты изображения для страницы №: 1 равны (0.0,226.21698), координаты изображения для страницы №: 2 равны (89.04, 524.354), координаты изображения для страницы № 3 равны (94.29 562,814).

3-е редактирование Код jQuery, который фиксирует координаты точки отбрасывания виджета сбрасываемой подписи:как это:

 $(".drop").droppable({
      accept: '.dragSigners',
      activeClass: "drop-area",

      drop: function(e, ui) {
        var off = $(this).offset();
        leftPosition  = ui.offset.left - off.left;
        topPosition   = ui.offset.top - off.top;
      }
 });

1 Ответ

1 голос
/ 19 июня 2019

Рисование изображений в вашем первом файле примера

Я пытался воспроизвести проблему следующим образом:

float CONVERSION_FACTOR_FROM_PIXEL_TO_POINT = 0.75f;
List<DocumentField> documentField = new ArrayList<>();

try (   InputStream resource = getClass().getResourceAsStream("Mix PDF.pdf");
        InputStream imageResource = getClass().getResourceAsStream("Signature.png") ) {
    byte[] imageBytes = StreamUtil.inputStreamToArray(imageResource);
    documentField.add(new DocumentField(0, "70", "600", "image", imageBytes));
    documentField.add(new DocumentField(1, "70", "600", "image", imageBytes));
    documentField.add(new DocumentField(2, "70", "600", "image", imageBytes));
    documentField.add(new DocumentField(3, "70", "600", "image", imageBytes));
    documentField.add(new DocumentField(4, "70", "600", "image", imageBytes));

    PdfReader pdfReader = new PdfReader(resource);
    PdfReader.unethicalreading=true;
    PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(new File(RESULT_FOLDER, "StampImagesLikeSubhenduMahanta.pdf")));
    for(DocumentField df:documentField){
        int pageNumber = df.getPageNumber()+1;
        PdfContentByte content = pdfStamper.getOverContent(pageNumber);
        Rectangle cropBox = pdfReader.getCropBox(pageNumber);
        if(pdfReader.getPageRotation(pageNumber) > 0) {
            float width = cropBox.getRight();
            cropBox.setRight(cropBox.getHeight());
            cropBox.setTop(width);                   
        }

        if(df.getFieldType().equals("image")){
            df.setxPosition(
                Float.parseFloat(df.getLeft())*
                CONVERSION_FACTOR_FROM_PIXEL_TO_POINT);
            df.setyPosition(Float.parseFloat(df.getTop())*CONVERSION_FACTOR_FROM_PIXEL_TO_POINT);
            float x = cropBox.getLeft()  + df.getxPosition();
            float y = cropBox.getTop()  - df.getyPosition();
            Image image = Image.getInstance(df.getFieldValue());
            image.scaleToFit(150*CONVERSION_FACTOR_FROM_PIXEL_TO_POINT, 50*CONVERSION_FACTOR_FROM_PIXEL_TO_POINT);
            image.setAbsolutePosition(x, y - 36f);
            content.addImage(image);
        }else if(df.getFieldType().equals("checkbox")){
            //...
        }else{
            //...
        }
    }
    pdfStamper.close(); 
}

( StampImages test testStampImagesLikeSubhenduMahanta)

с этим классом POJO

class DocumentField {
    DocumentField(int pageNumber, String left, String top, String fieldType, byte[] fieldValue) {
        this.pageNumber = pageNumber;
        this.left = left;
        this.top = top;
        this.fieldType = fieldType;
        this.fieldValue = fieldValue;
    }

    int getPageNumber()                 {   return pageNumber;          }
    final int pageNumber;
    String getLeft()                    {   return left;                }
    final String left;
    String getTop()                     {   return top;                 }
    final String top;
    String getFieldType()               {   return fieldType;           }
    final String fieldType;
    byte[] getFieldValue()              {   return fieldValue;          }
    final byte[] fieldValue;
    float getxPosition()                {   return xPosition;           }
    void setxPosition(float xPosition)  {   this.xPosition = xPosition; }
    float xPosition = 0;
    float getyPosition()                {   return yPosition;           }
    void setyPosition(float yPosition)  {   this.yPosition = yPosition; }
    float yPosition = 0;
}

( StampImages класс помощника)

В комментарии вы сказали:

Я подписываюсь в одном месте на всех 5 страницах.

Таким образом, я использовал left значения 70 и top значения 600 для всех DocumentField экземпляров

documentField.add(new DocumentField(0, "70", "600", "image", imageBytes));
documentField.add(new DocumentField(1, "70", "600", "image", imageBytes));
documentField.add(new DocumentField(2, "70", "600", "image", imageBytes));
documentField.add(new DocumentField(3, "70", "600", "image", imageBytes));
documentField.add(new DocumentField(4, "70", "600", "image", imageBytes));

но результат выглядит так:

screenshot

Как видите, изображения подписи находятся там, где их можно ожидать.

Таким образом, я не могу воспроизвести вашу проблему.

Вы должны проверить значения всех DocumentField экземпляров и проверить их правильность.

Анализ значений базы данных для вашего второго файла примера

Этот второй пример PDF имеет 3 страницы, размеры для 1-й страницы 682,04 x 297,12, 2-й страницы 610,52 x 788,6, 3-я страница почти такая же, как 2-ая страница 611 X 789,08. [...]

Затем я попытался разместить подпись в нижнем левом углу каждой страницы. Это не удалось. Я сохраняю координаты изображения, перетаскиваемого в базу данных, и значения (0, 350,484), (0,352,328) и (7, 301.688). [...]

Теперь на 1-й странице подпись вставляется в нужном месте. Но для 2-й и 3-й страницы они являются почти серединой страницы в направлении у

Учитывая, что вторая и третья страницы более чем в два раза превышают первую, используя приблизительно одинаковое значение базы данных y (верхняя часть y поля в пикселях от верхней части видимой страницы) на всех страницах (страница 1: ок. 350, стр. 2: около 350, стр. 3: около 300), вероятно, будут иметь совершенно разные визуальные эффекты: эти значения базы данных, очевидно, поместят подпись на среднюю высоту на второй и третьей страницах.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...