当前位置: 首页 > 知识库问答 >
问题:

如何使用pdfbox在另一个PDPage中插入PDPage

陈泰宁
2023-03-14

我使用不同的工具,如处理来创建矢量图。这些图被写成单页或多页pdf。我想使用pdfbox将这些图包含在单个类似报告的pdf中。

我当前的工作流程包括这些PDF作为图像,并带有以下伪代码

PDDocument inFile = PDDocument.load(file);
PDPage firstPage = (PDPage) inFile.getDocumentCatalog().getAllPages().get(0);
BufferedImage image = firstPage.convertToImage(BufferedImage.TYPE_INT_RGB, 300);
PDXObjectImage ximage = new PDPixelMap(document, image);

PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.drawXObject(ximage, 0, 0, ximage.getWidth(), ximage.getHeight());
contentStream.close();

虽然这有效,但它失去了矢量文件格式的好处,特别是文件/大小与打印质量。

是否可以使用pdfbox将其他pdf页面作为嵌入对象包含在页面中(未作为单独页面添加)?例如,我可以使用PDStream吗?我更喜欢像pdflex这样的解决方案能够将pdf图形嵌入到新的pdf文档中。

对于该任务,您可以推荐哪些其他Java库?

共有3个答案

裴韬
2023-03-14

正如mkl恰当地建议的,PDFClown是为页面嵌入提供显式支持的Java库之一(所谓的FormXObject(参见PDF参考1.7,§4.9))。

为了让您了解PDFClown的工作方式,以下代码代表了mkl的PDFBox解决方案的等价物(注意:正如mkl后来所说,他的代码示例绝非优化,因此此比较可能不对应PDFBox的实际状态——欢迎评论澄清这一点):

Document source = new File(SOURCE).getDocument();
Pages sourcePages = source.getPages();

Document target = new File().getDocument();
Page targetPage = new Page(target);
target.getPages().add(targetPage);

XObject xobject = sourcePages.get(0).toXObject(target);

PrimitiveComposer composer = new PrimitiveComposer(targetPage);
Dimension2D targetSize = targetPage.getSize();
Dimension2D sourceSize = xobject.getSize();
composer.showXObject(xobject, new Point2D.Double(targetSize.getWidth() * .5, targetSize.getHeight() * .35), new Dimension(sourceSize.getWidth() * .6, sourceSize.getHeight() * .6), XAlignmentEnum.Center, YAlignmentEnum.Middle, 45);
composer.showXObject(xobject, new Point2D.Double(targetSize.getWidth() * .35, targetSize.getHeight()), new Dimension(sourceSize.getWidth() * .4, sourceSize.getHeight() * .4), XAlignmentEnum.Left, YAlignmentEnum.Top, 90);
composer.flush();

target.getFile().save(TARGET, SerializationModeEnum.Standard);
source.getFile().close();

将此代码与PDFBox的等效代码进行比较,您可以注意到一些相关的差异,这些差异显示了PDFClown更整洁的风格(如果一些PDFBox专家可以验证我的断言,那就太好了):

  • Page-to-FormXObject转换:PDFClown本机支持专用方法(Page.toXObject()),因此不需要额外的繁重工作,例如帮助方法import AsXObject();
  • 资源管理:PDFClown自动(透明地)分配页面资源,因此不需要显式调用,例如page.getResources(). addXObject(xject,"X");
  • XObject绘图:PDFClown支持高级(显式缩放、平移和旋转锚)和低级(仿射转换)方法将您的FormXObject放置到页面中,因此不需要处理仿射转换。

关键是PDFClown具有由多个抽象层组成的丰富架构:根据您的要求,您可以选择最合适的编码风格(要么深入研究PDF的低级基本结构,要么利用其方便优雅的高级模型)。PDFClown让您可以随心所欲地调整每个字节并通过简单得可笑的方法调用解决复杂的任务。

披露:我是PDFClown的首席开发人员。

薛文斌
2023-03-14

要更新此问题:

组织中已经有一个助手类。阿帕奇。pdfbox。多重DF。LayerTubility进行导入。

演示将PDF页面叠加到另一个PDF上的示例:叠加页面。

此类是Apache PDFBox示例的一部分,并将@mkl所示的示例转换添加到其中。

叶德本
2023-03-14

是否可以使用pdfbox将其他pdf页面作为嵌入对象包含在页面中

这应该是可能的。PDF格式允许使用所谓的表单x对象作为这样的嵌入式对象。不过,我没有看到明确的实现,但该过程与PageExtractorPDFMerger实用程序所做的足够相似。

使用PDFBox 2.0.0开发版本的当前SNAPSHOT从PageExtractor派生的概念证明:

PDDocument source = PDDocument.loadNonSeq(SOURCE, null);
List<PDPage> pages = source.getDocumentCatalog().getAllPages();

PDDocument target = new PDDocument();
PDPage page = new PDPage();
PDRectangle cropBox = page.findCropBox();
page.setResources(new PDResources());
target.addPage(page);

PDFormXObject xobject = importAsXObject(target, pages.get(0));
page.getResources().addXObject(xobject, "X");

PDPageContentStream content = new PDPageContentStream(target, page);
AffineTransform transform = new AffineTransform(0, 0.5, -0.5, 0, cropBox.getWidth(), 0);
content.drawXObject(xobject, transform);
transform = new AffineTransform(0.5, 0.5, -0.5, 0.5, 0.5 * cropBox.getWidth(), 0.2 * cropBox.getHeight());
content.drawXObject(xobject, transform);
content.close();

target.save(TARGET);
target.close();
source.close();

此代码将源文档的第一页作为XObject导入目标文档,并将其两次放入具有不同缩放和旋转转换的页面上,例如对于此源

它创造了这个

实际执行导入的helper方法importAsXObject定义如下:

PDFormXObject importAsXObject(PDDocument target, PDPage page) throws IOException
{
    final PDStream src = page.getContents();
    if (src != null)
    {
        final PDFormXObject xobject = new PDFormXObject(target);

        OutputStream os = xobject.getPDStream().createOutputStream();
        InputStream is = src.createInputStream();
        try
        {
            IOUtils.copy(is, os);
        }
        finally
        {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(os);
        }

        xobject.setResources(page.findResources());
        xobject.setBBox(page.findCropBox());

        return xobject;
    }
    return null;
}

如上所述,这只是概念证明,尚未考虑角落案例。

 类似资料:
  • 我的pl/sql代码有问题。问题是:当我使用tns(用于远程数据库连接)尝试正常插入时,一切都正常 ORA-06512:a ligne 36 02069。00000-“此操作的全局_名称参数必须设置为TRUE”*原因:需要语句的远程映射,但无法实现,因为要实现它,全局_名称应设置为TRUE*操作:如果可能,发出alter session set global_名称=TRUE 问题是,当我将全局_名

  • 我正在研究布局必须非常整洁和准确的PDF文档的选项。 文档是一种报告,在现有背景上显示数据。在某些情况下,文本比它应该容纳的房间大。 我想将文本剪辑到允许的精确区域(这不是包装或“省略”,因为文本是大多数时间的数字)。 这是我想要的效果(这是一个例子,我不是想缩短字符串,我想让字符串保持不变,但实际上是在允许的范围外被剪断)。 谢谢,吉咪

  • 喂 我有一个文档,看起来像这样: 我尝试使用$push添加另一个街道文档,它错误地出现: pymongo.errors。WriteError:字段“地址”必须是数组,但在文档{_id:ObjectId('6049e88657e43d8801197c72')}中属于object类型 我正在使用的代码: 没有制作地址簿或任何东西,只是编辑它,这样它对没有上下文的人来说更有意义。 我想要的输出是文档如下

  • 问题内容: 我必须用表格制作PDF。到目前为止,它工作正常,但现在我想添加包装功能。所以我需要插入换行符。 我想在“插入”之前添加“”。我尝试了“ ”,这是换行的十六进制值,但是Eclipse显示了一个错误。 是否可以使用drawString添加换行符? 问题答案: pdf格式不知道换行符。您必须使用moveTextPositionByAmount拆分字符串并将文本位置移至下一行。 这不是特殊的“

  • 这是我的php文件...我想在第二个表成功插入后更新第一个表,我要选择并正确插入,但我想更新的行在数据插入后没有更新。 有人能告诉我如何写这在PHP mysqli程序的方式。

  • 问题内容: 还有在JavaScript,但我怎么能插入一个元素 后, 另一种元素,而不使用jQuery或其他库? 问题答案: referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); 您要放置的节点在哪里。If 是其父元素中的最后一个子元素,这很好,因为它将是,并通过添加到列表的末尾来处理这种情况。 所以: