我正在使用PDF Box处理PDF文件,并根据页面上给定的坐标插入文本对象。我得到的坐标是左上角的,我找到页面的媒体框,然后计算文本的位置。然而,有一些PDF图像(它们被扫描),我插入的文本没有站在正确的位置,就像页面的大小比媒体盒大得多。
// getX-Y returns the coordinates that the text should be inserted
// getSize returns the text height
void write(PDDocument doc, PDPage page, PDPageContentStream cs) {
PDRectangle rect = page.findMediaBox();
cs.moveTextPositionByAmount(this.getX(), height-this.getY()-getSize());
}
从媒体框中返回的尺寸为595.2 x 841.92
。对于给定的文本位置300x420
,我希望将此文本插入页面中间。但是它的插入方式太低而且页面左侧。当我用Acrobat Reader打开文档并将页面复制为图像时(因为它已被扫描),我看到图像尺寸为2480 x 3508
。如果页面尺寸为该尺寸,则插入文本的位置将有意义。
我觉得pdf页面大小会根据其内容进行更改,但为什么我不将这些尺寸作为页面大小进行更改,而是仍然得到类似595.2 x 841.92
的内容?我应该处理页面上的每个图像并找到真正的尺寸吗?我在这里缺少什么?
编辑:
这是我得到的代码部分PDPageContentStream
:
PDDocument doc = null;
doc = PDDocument.load(inputFile);
List <?> allPages = doc.getDocumentCatalog().getAllPages();
for (int i = 0; i < list.size(); i++) {
PDFObject obj = (PDFObject) list.get(i);
for (int j = 0; j < allPages.size(); j++) {
PDPage page = (PDPage) allPages.get(j);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
obj.write(doc, page, contentStream);
if ("F".equalsIgnoreCase(obj.getPageType())) {
break;
}
}
}
答案 0 :(得分:1)
不幸的是,OP没有发布所有相关代码。因此,这个答案部分基于假设,特别是他创建了他的PDPageContentStream
而没有确保默认用户空间坐标系仍然在他添加新操作的位置使用。
第一页的内容流开头如下:
0.24000 0 0 0.24000 0 0 cm
q
2480 0 0 3508 0 0 cm
/Im5 Do
Q
因此,它首先按.24
缩放用户空间坐标系,按下图形状态,将坐标系缩放2480
(x方向)和3508
(y方向),绘制图像,最终恢复图形状态。
因此,此后用户空间坐标系仍然由.24
缩放。因此,以下操作中给出的坐标受该因素的影响。
紧接着是文本对象,例如这样:
BT
1 0 0 rg
/F0 25 Tf
400 794.9199829102 Td
(JFE14006) Tj
ET
我认为这是OP添加的对象之一,没有考虑非默认用户空间坐标系,因为坐标和字体大小似乎足以用于默认的用户空间坐标系。
(顺便说一句,所引用的字体未在页面的资源字典中定义。)
当插入点的用户空间坐标系缩放.24时,您可以反缩放自己的坐标和大小(即将它们除以.24)。
E.g。要使用大小为10的字体在给定的给定文本位置300x420(原点在左上角)绘制文本“MIDDLE”,您可以这样做:
PDDocument document = PDDocument.load("0006-sun1-4.pdf");
List<PDPage> allPages = document.getDocumentCatalog().getAllPages();
PDPage firstPage = allPages.get(0);
PDRectangle pageSize = firstPage.findMediaBox();
PDPageContentStream contentStream = new PDPageContentStream(document, firstPage, true, true);
contentStream.setStrokingColor(Color.red);
contentStream.beginText();
contentStream.moveTextPositionByAmount(300/.24f, (pageSize.getUpperRightY() - 420 - 10)/.24f);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 10/.24f);
contentStream.drawString("MIDDLE");
contentStream.endText();
contentStream.close();
document.save("0006-sun1-4-scaledAdd.pdf");
document.close();
此解决方案并非最佳,但是:
因此:
您可以通过使用 q (保存图形状态)和 Q (恢复图形状态)运算符对封装现有内容流来恢复对图形状态的所有更改。
E.g。如上所述,使用大小为10的字体在给定的给定文本位置300x420(来自左上角)绘制文本“MIDDLE”,您可以这样做:
PDDocument document = PDDocument.load("0006-sun1-4.pdf");
List<PDPage> allPages = document.getDocumentCatalog().getAllPages();
PDPage firstPage = allPages.get(0);
PDRectangle pageSize = firstPage.findMediaBox();
PDStream contents = firstPage.getContents();
PDFStreamParser parser = new PDFStreamParser(contents.getStream());
parser.parse();
List<Object> tokens = parser.getTokens();
tokens.add(0, PDFOperator.getOperator("q"));
tokens.add(PDFOperator.getOperator("Q"));
PDStream updatedStream = new PDStream(document);
OutputStream out = updatedStream.createOutputStream();
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens(tokens);
firstPage.setContents(updatedStream);
PDPageContentStream contentStream = new PDPageContentStream(document, firstPage, true, true);
contentStream.setStrokingColor(Color.red);
contentStream.beginText();
contentStream.moveTextPositionByAmount(300, pageSize.getUpperRightY() - 420 - 10);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 10);
contentStream.drawString("MIDDLE");
contentStream.endText();
contentStream.close();
document.save("0006-sun1-4-restoredAdd.pdf");
document.close();
(在基本上只绘制图像的页面的情况下,解析和重写现有流不是完全合适的样式资源,但不是真正的问题。)