我在实现中适用于简单情况,但不适用于复杂情况。原始pdf显示在中央窗格中。我有一个侧窗格,其中有一些矩形,例如“名称”,“签名”,“时间戳”,可以将其拖到pdf上。使用jQuery可拖动和可拖放,我能够捕获放置点的坐标并将其存储在数据库中。使用iText的PdfStamper
,我得到PdfContentByte
,并向其中添加签名图像。如果pdf文档是同类文档,则可以正常工作-假设所有页面均为Letter尺寸。但是如果页面是横向和纵向混合使用,则失败。签名被嵌入在横向页面的适当位置,但没有嵌入纵向页面的适当位置。如果所有页面都是横向的,那么就没有问题。同样,如果所有页面都是纵向的,那么也没问题。
我了解图像以像素为单位,而pdf尺寸 以点。所以我已经将像素的图像坐标转换为 点(0.75)。还考虑到图像原点位于左上方
角,而在pdf中,原点在左下角,对于图像y轴是 向南,但对于pdf,y轴是向北。
如何处理?
编辑:
这里是代码:
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 with both Landscape & Portrait, I am always signing at same place
第二次修改
此第二个示例pdf有3页,尺寸分别为:第一页682.04 x 297.12,第二页610.52 x 788.6,第三页与第二页611 X 789.08几乎相同。首先,我尝试将签名放置在每页的左上角。然后我尝试将签名放置在每页的左下角,但没有成功,我将图像的坐标存储到数据库中,值分别为(0,350.484),(0,352.328)和(7, 301.688)。第三个值的x坐标应为0,我们可以忽略此小偏差。现在对于第一页,签名被嵌入到正确的位置。但是对于第二和第三页,它们几乎是页面在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;
}
});
答案 0 :(得分:1)
我试图重现这样的问题:
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测试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页中的同一位置签名。
因此,我为所有70
实例使用了 left 值600
和 top 值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));
但是结果看起来像这样:
如您所见,签名图像是人们期望的位置。
因此,我无法复制您的问题。
您应该检查所有DocumentField
实例的值并检查其正确性。
此第二个示例pdf有3页,尺寸分别为:第一页682.04 x 297.12,第二页610.52 x 788.6,第三页与第二页611 X 789.08几乎相同。 [...]
然后我尝试将签名放置在每页的左下角,但没有成功。我正在存储拖动到数据库的图像坐标,值分别为(0,350.484),(0,352.328)和(7,301.688)。 [...]
现在,在第一页中,签名被嵌入到正确的位置。但是对于第二页和第三页,它们几乎是y方向上的页面中间
请考虑到第二页和第三页是第一页的两倍多,并在所有页上使用大致相同的数据库y(以像素为单位,从可见页的顶部开始,以像素为单位的字段的y)值。 350,第2页:约350,第3页:约300)可能具有完全不同的视觉效果:这些数据库值显然会将签名放在第二页和第三页的中间高度。
因此,数据库中的值根本没有任何意义。请检查生成和存储这些坐标的过程。