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

时间:2015-02-03 09:50:49

标签: java pdf pdfbox

如果页面大小不同,如何将外部pdf文档中的页面添加到目标pdf? 这是我想要完成的事情: enter image description here

我尝试使用LayerUtility(就像在此示例PDFBox LayerUtility - Importing layers into existing PDF中一样),但是一旦我从外部pdf导入页面,该过程就会挂起:

PDDocument destinationPdfDoc = PDDocument.load(fileInputStream);
PDDocument externalPdf = PDDocument.load(EXTERNAL PDF);

List<PDPage> 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();

我做错了什么?

1 个答案:

答案 0 :(得分:5)

PDFBox依赖项

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

在评论中,OP澄清了

  

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

由于这听起来可能有异常或错误,因此在聊天中提议尝试将代码封装为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 ...

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

PDFBox版本1.8.x依赖项描述为here。特别是有三个核心组件 pdfbox fontbox jempbox 所有这些组件都应存在于同一版本中,并且需要依赖 commons-logging

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

定位导入的页面

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

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

Source page from test-pdf.pdf

已添加到此页面

enter image description here

导致了这个页面

result of the OP's original code

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());

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

result using the translation above

PDFBox LayerUtility的期望

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

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

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

不幸的是,此构造函数生成的内容流将继承目标页面现有内容末尾的图形状态。这尤其意味着用户空间坐标系可能不再处于其默认状态。一些软件例如镜像坐标系使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");