Java 如何使用iText将签名附加到pdf?

Java 如何使用iText将签名附加到pdf?,java,jquery,pdf,itext,Java,Jquery,Pdf,Itext,我在实现中使用了一种方法,它适用于简单的情况,但不适用于复杂的情况。原始pdf显示在中央窗格中。我有一个侧窗格,其中有一些矩形,如“名称”、“签名”、“时间戳”,可以在pdf上拖动。使用jquerydraggable和droppable,我能够捕获放置点的坐标并将其存储在数据库中。使用iText的PdfStamper,我得到PdfContentByte&我将签名图像添加到它。如果pdf文档是同质的——比如说所有页面都是字母大小的,它就可以工作。但如果页面是横向和纵向的混合,则会失败。签名嵌入在横

我在实现中使用了一种方法,它适用于简单的情况,但不适用于复杂的情况。原始pdf显示在中央窗格中。我有一个侧窗格,其中有一些矩形,如“名称”、“签名”、“时间戳”,可以在pdf上拖动。使用jquerydraggable和droppable,我能够捕获放置点的坐标并将其存储在数据库中。使用iText的
PdfStamper
,我得到
PdfContentByte
&我将签名图像添加到它。如果pdf文档是同质的——比如说所有页面都是字母大小的,它就可以工作。但如果页面是横向和纵向的混合,则会失败。签名嵌入在横向页面的适当位置,而不是纵向页面的适当位置。如果所有页面都是横向的,那么就没有问题了。同样,如果所有页面都是纵向的,那么也没有问题

我知道图像是以像素为单位测量的,而pdf尺寸是以像素为单位测量的 这些都是重点。所以我把图像坐标转换成像素 点(0.75)。还应考虑到,对于图像,原点位于左上角
角,而在pdf中,原点位于左下角,对于图像,y轴为 向南,但对于pdf,y轴是向北

怎么办

编辑:

下面是代码:
DocumentField
是一个POJO,它具有签名坐标的属性

在第一个示例文件上绘制图像 我试着像这样重现这个问题:

 $(".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;
      }
 });
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(); 
}
(辅助班)

你在评论中说:

我在5页的同一个地方签名

因此,我对所有
DocumentField
实例使用左值
70
和顶值
600

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));
但结果是这样的:

 $(".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;
      }
 });
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(); 
}

正如您所看到的,签名图像是人们所期望的

因此,我无法复制您的问题

您应该检查所有
DocumentField
实例的值并检查其正确性

分析第二个示例文件的数据库值 第二个示例pdf有3页,尺寸为第1页682.04 x 297.12,第2页610.52 x 788.6,第3页与第2页611 x 789.08几乎相同。[……]

然后我尝试将签名放在每页的左下角,但没有成功。我正在存储拖到数据库中的图像坐标&值为(0352.328)和(7301.688)。[……]

现在,在第1页,签名被嵌入到正确的位置。但对于第2页和第3页,它们几乎位于y方向的页面中间

考虑到第二页和第三页的高度是第一页的两倍以上,在所有页面上使用大致相同的数据库y(从可见页面顶部开始的像素字段顶部y)值(第1页:约350,第2页:约350,第3页:约300)可能会有完全不同的视觉效果:这些数据库值显然会将签名放在第二页和第三页的中间高度


因此,数据库中的值根本没有意义。请检查生成和存储这些坐标的过程。

“签名嵌入在横向页面的适当位置,而不是纵向页面的适当位置。”-这听起来像是您错误地计算了用于定位数据的坐标。如果没有关键代码,很难更详细地说明。@mkl我添加了代码。我假设您在横向和纵向之间切换时应用了页面旋转,而不是在不同的cropbox值之间切换,这是因为在检索框时不考虑页面旋转,但在定位时考虑了iText页面上的材料。稍后我会更深入地研究这个问题。你能分享一个你观察到问题的示例文档吗?@mkl我已经添加了pdf。我在5页的同一个地方签名。请参考问题中的链接。您应该将第三个问题作为单独的问题进行编辑。乍一看你的问题读者会把它看作是java和iTXT的中心。没有人会期望其中包含javascript/jQuery问题。因此,几乎没有任何javascript/jQuery专家会通读到最后。感谢您为帮助我付出了巨大的努力。我已经编辑了我的问题。@Subhundumahanta您能确定代码在第一个示例文件中使用意外坐标的原因吗?我会看看你的新档案,很可能是下周我回来之前。