java - 图像更宽的 PDF 页面大小

标签 java pdf pdfbox

我正在使用 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 的东西?我应该处理页面上的每个图像并找到真实尺寸吗?我在这里缺少什么?

编辑: Sample PDF Document

编辑: 这是我得到的代码部分 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;
        }
    }
}

最佳答案

不幸的是,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添加的对象之一,没有考虑非默认用户空间坐标系,因为坐标和字体大小对于默认用户空间坐标系来说似乎足够了。

(顺便说一句,页面的资源字典中没有定义引用的字体。)

解决方案1

由于插入点处的用户空间坐标系按 0.24 缩放,因此您可以对自己的坐标和大小进行反缩放(即将它们除以 0.24)。

例如要使用大小为 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();

但是这个解决方案并不是最佳的:

  • 一旦您有了另一个源文档(例如更新的表单),插入点处的内容流可能会具有不同比例的坐标系;
  • 图形绘制引擎的其他状态也可能未达到您期望的默认状态。

因此:

解决方案2

您可以通过用q(保存图形状态)和Q(恢复图形状态)运算符对封闭现有内容流来恢复对图形状态的所有更改。

例如如上所示,使用大小为 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();

(解析和重写现有流在资源方面并不是很好的风格,但对于基本上只绘制图像的页面来说并不是一个真正的问题。)

Screenshot of result

关于java - 图像更宽的 PDF 页面大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21735767/

相关文章:

java - 如何用 Java 录制网络摄像头视频?

javascript - 使用客户端 JavaScript 将文件附加到 PDF?

java - 免费的开源 Java 库,用于转换 PDF - 图像、PDF - HTML、PDF - 提取图像和文本

java - JVM内存使用失控

java - 如何检查 fragment 中的权限

java - 在 Spring boot 和 REST API 中上传 multipart/form-data 文件

pdf - 如何使用 pandoc 设置图像的替代文本以进行 docx 转换

c# - 将具有透明度的 PDF 转换为无光栅化的 EPS

java - 使用Java读取Excel中嵌入的pdf文件

JAVA pdfbox PDF 到非常简单的 HTML