简体   繁体   English

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

[英]Add page as layer from separate pdf(different page size) using pdfbox

How can I add a page from external pdf doc to destination pdf if pages have different sizes? 如果页面大小不同,如何将外部pdf文档中的页面添加到目标pdf? Here is what I'd like to accomplish: 这是我想要完成的事情: 在此输入图像描述

I tried to use LayerUtility (like in this example PDFBox LayerUtility - Importing layers into existing PDF ), but once I import page from external pdf the process hangs: 我尝试使用LayerUtility(就像在这个例子中PDFBox LayerUtility - 将图层导入到现有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();

What I'm doing wrong? 我做错了什么?

PDFBox dependencies PDFBox依赖项

The main issue was that PDFBox has three core components and one required dependency. 主要问题是PDFBox有三个核心组件,一个需要依赖。 One core component was missing. 缺少一个核心组件。

In comments the OP clarified that OP在评论中澄清了这一点

Actually process doesn't hangs, the file is just not created at all. 实际上进程没有挂起,文件根本就没有创建。

As this sounds like there might have been an exception or error, trying to envelope the code as a try { ... } catch (Throwable t) { t.printStackTrace(); } 因为这听起来可能有异常或错误,尝试将代码包装为try { ... } catch (Throwable t) { t.printStackTrace(); } try { ... } catch (Throwable t) { t.printStackTrace(); } block has been proposed in chat. try { ... } catch (Throwable t) { t.printStackTrace(); }已经在聊天中被提出。 And indeed, 事实上,

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 ...

As it turned out, fontbox.jar was missing from the OP's setup. 事实证明,OP的设置中缺少fontbox.jar。

The PDFBox version 1.8.x dependencies are described here . 此处描述 PDFBox版本1.8.x依赖项。 Especially there are the three core components pdfbox , fontbox , and jempbox all of which shall be present in the same version, and there is the required dependency commons-logging . 特别是有三个核心组件pdfboxfontboxjempbox,所有这些组件都应存在于同一版本中,并且存在所需的依赖性commons-logging

As soon as the missing component had been added, the sample worked properly. 一旦添加了缺失的组件,样本就能正常工作。

Positioning the imported page 定位导入的页面

The imported page can be positioned on the target page by means of a translation in the AffineTransform parameter. 可以通过AffineTransform参数中的转换将导入的页面定位在目标页面上。 This parameter also allows for other transformations, eg to scale, rotate, mirror, skew,...* 此参数还允许其他变换,例如缩放,旋转,镜像,倾斜,...... *

For the original sample files this PDF page 对于原始样本文件,此PDF页面

来自test-pdf.pdf的源页面

was added onto onto this page 被添加到此页面上

在此输入图像描述

which resulted in this page 这导致了这个页面

OP原始代码的结果

The OP then wondered OP然后想知道

how to position the imported layer 如何定位导入的图层

The parameter for that in the layerUtility.appendFormAsLayer call is the AffineTransform affineTransform . layerUtility.appendFormAsLayer调用中的参数是AffineTransform affineTransform The OP used new AffineTransform() here which creates an identity matrix which in turn causes the source page to be added at the origin of coordinate system, in this case at the bottom. OP在这里使用了new AffineTransform() ,它创建了一个单位矩阵,这又使得源页面被添加到坐标系的原点,在本例中是在底部。

By using a translation instead of the identity, eg 通过使用翻译而不是身份,例如

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

one can position the source page elsewhere, eg at the top: 可以将源页面放在其他位置,例如在顶部:

结果使用上面的翻译

PDFBox LayerUtility's expectations PDFBox LayerUtility的期望

Unfortunately it turns out that layerUtility.appendFormAsLayer appends the form to the page without resetting the graphics context. 不幸的是,事实证明, layerUtility.appendFormAsLayer将表单附加到页面而不重置图形上下文。

layerUtility.appendFormAsLayer uses this code to add an additional content stream: layerUtility.appendFormAsLayer使用此代码添加其他内容流:

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

Unfortunately a content stream generated by this constructor inherits the graphics state as is at the end of the existing content of the target page. 遗憾的是,此构造函数生成的内容流将继承目标页面现有内容末尾的图形状态。 This especially means that the user space coordinate system may not be in its default state anymore. 这尤其意味着用户空间坐标系可能不再处于其默认状态。 Some software eg mirrors the coordinate system to have y coordinates increasing downwards. 一些软件例如镜像坐标系以使y坐标向下增加。

If instead 如果相反

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

had been used, the graphics state would have been reset to its default state and, therefore, be known. 如果已经使用过,图形状态将被重置为默认状态,因此可以知道。

By itself, therefore, this method is not usable in a controlled manner for arbitrary input. 因此,该方法本身不能以受控方式用于任意输入。

Fortunately, though, the LayerUtility also has a method wrapInSaveRestore(PDPage) to overcome this weakness by manipulating the content of the given page to have the default graphics state at the end. 幸运的是, LayerUtility还有一个方法wrapInSaveRestore(PDPage) ,通过操纵给定页面的内容以在结尾处具有默认图形状态来克服这个弱点。

Thus, one should replace 因此,人们应该取而代之

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

by 通过

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM