使用pdfbox从单独的pdf(不同页面大小)添加页面作为图层

如果页面大小不同,如何将外部pdf文档中的页面添加到目标pdf? 这是我想要完成的事情: 在此处输入图像描述

我尝试使用LayerUtility(就像在这个例子中PDFBox LayerUtility – 将图层导入到现有PDF中 ),但是一旦我从外部pdf导入页面,该过程就会挂起:

PDDocument destinationPdfDoc = PDDocument.load(fileInputStream); PDDocument externalPdf = PDDocument.load(EXTERNAL PDF); List destinationPages = destinationPdfDoc.getDocumentCatalog().getAllPages(); LayerUtility layerUtility = new LayerUtility(destinationPdfDoc); // process hangs here PDXObjectForm firstForm = layerUtility.importPageAsForm(externalPdf, 0); AffineTransform affineTransform = new AffineTransform(); layerUtility.appendFormAsLayer(destinationPages.get(0), firstForm, affineTransform, "external page"); destinationPdfDoc.save(resultTempFile); destinationPdfDoc.close(); externalPdf.close(); 

我做错了什么?

PDFBox依赖项

主要问题是PDFBox有三个核心组件,一个需要依赖。 缺少一个核心组件。

OP在评论中澄清了这一点

实际上进程没有挂起,文件根本就没有创建。

因为这听起来可能有exception或错误,尝试将代码包装为try { ... } catch (Throwable t) { t.printStackTrace(); } 已经在聊天中提出了阻止 。 事实上,

 java.lang.NoClassDefFoundError: org/apache/fontbox/util/BoundingBox at org.apache.pdfbox.util.LayerUtility.importPageAsForm(LayerUtility.java:203) at org.apache.pdfbox.util.LayerUtility.importPageAsForm(LayerUtility.java:135) at ... 

事实certificate,OP的设置中缺少fontbox.jar。

此处描述了 PDFBox版本1.8.x依赖项。 特别是有三个核心组件pdfboxfontboxjempbox,所有这些组件都应存在于同一版本中,并且存在所需的依赖性commons-logging

一旦添加了缺失的组件,样本就能正常工作。

定位导入的页面

可以通过AffineTransform参数中的转换将导入的页面定位在目标页面上。 此参数还允许其他变换,例如缩放,旋转,镜像,倾斜,…… *

对于原始样本文件,此PDF页面

来自test-pdf.pdf的源页面

被添加到此页面上

在此处输入图像描述

这导致了这个页面

OP原始代码的结果

OP然后想知道

如何定位导入的图层

layerUtility.appendFormAsLayer调用中的参数是AffineTransform affineTransform 。 OP在这里使用了new AffineTransform() ,它创建了一个单位矩阵,这又使得源页面被添加到坐标系的原点,在这种情况下是在底部。

通过使用翻译而不是身份,例如

 PDRectangle destCrop = destinationPages.get(0).findCropBox(); PDRectangle sourceBox = firstForm.getBBox(); AffineTransform affineTransform = AffineTransform.getTranslateInstance(0, destCrop.getUpperRightY() - sourceBox.getHeight()); 

可以将源页面放在别处,例如在顶部:

结果使用上面的翻译

PDFBox LayerUtility的期望

不幸的是,事实certificate, layerUtility.appendFormAsLayer将表单附加到页面而不重置图形上下文。

layerUtility.appendFormAsLayer使用此代码添加其他内容流:

 PDPageContentStream contentStream = new PDPageContentStream( targetDoc, targetPage, true, !DEBUG); 

遗憾的是,此构造函数生成的内容流将inheritance目标页面现有内容末尾的图形状态。 这尤其意味着用户空间坐标系可能不再处于其默认状态。 一些软件例如镜像坐标系以使y坐标向下增加。

如果相反

 PDPageContentStream contentStream = new PDPageContentStream( targetDoc, targetPage, true, !DEBUG, true); 

如果已经使用过,图形状态将被重置为默认状态,因此可以知道。

因此,该方法本身不能以受控方式用于任意输入。

幸运的是, LayerUtility还有一个方法wrapInSaveRestore(PDPage) ,通过操纵给定页面的内容来最终获得默认的图形状态来克服这个弱点。

因此,应该取代

 layerUtility.appendFormAsLayer(destinationPages.get(0), firstForm, affineTransform, "external page"); 

通过

 PDPage destPage = destinationPages.get(0); layerUtility.wrapInSaveRestore(destPage); layerUtility.appendFormAsLayer(destPage, firstForm, affineTransform, "external page");