Java 如何使用pdfbox在另一个PDPage中插入PDPage
我使用不同的工具,如处理来创建矢量图。这些绘图以单页或多页PDF格式编写。我想使用pdfbox将这些图包含在一个单独的报告中,如pdf 我当前的工作流程将这些PDF作为图像包含在下面的伪代码中Java 如何使用pdfbox在另一个PDPage中插入PDPage,java,pdf,pdfbox,Java,Pdf,Pdfbox,我使用不同的工具,如处理来创建矢量图。这些绘图以单页或多页PDF格式编写。我想使用pdfbox将这些图包含在一个单独的报告中,如pdf 我当前的工作流程将这些PDF作为图像包含在下面的伪代码中 PDDocument inFile = PDDocument.load(file); PDPage firstPage = (PDPage) inFile.getDocumentCatalog().getAllPages().get(0); BufferedImage image = firstPage.
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吗?我更喜欢pdflatex这样的解决方案,它能够将pdf图形嵌入到新的pdf文档中
对于该任务,您可以推荐哪些其他Java库
是否可以使用pdfbox将其他pdf页面作为嵌入对象包含在页面中
这应该是可能的。PDF格式允许使用所谓的表单XObject作为此类嵌入对象。虽然我没有看到一个明确的实现,但是这个过程与PageExtractor
或PDFMergerUtility
所做的非常相似
使用PDFBox 2.0.0开发版本的当前快照从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();
如上所述,这只是一个概念证明,尚未考虑角落案例。正如mkl适当建议的那样,是为页面嵌入提供明确支持的Java库之一(所谓的表单XObject(参见PDF参考1.7,§4.9)) 为了让您了解PDFClown的工作方式,以下代码代表了mkl的PDFBox解决方案(注意:正如mkl后来所说,他的代码示例并没有经过优化,因此此比较可能与PDFBox的实际状态不符——欢迎评论以澄清这一点): 将此代码与PDFBox的等效代码进行比较,您可以注意到一些相关的差异,这些差异显示了PDFClown的整洁风格(如果一些PDFBox专家能够验证我的断言,那就太好了):
- 页面到表单对象的转换:PDFClown本机支持专用方法(Page.toXObject()),因此不需要额外的繁重工作,例如帮助器方法importAsXObject()李>
- 资源管理:PDFClown自动(透明)分配页面资源,因此不需要显式调用,例如page.getResources().addXObject(xobject,“X”)李>
- XObject绘图:PDFClown支持高级(显式缩放、平移和旋转定位)和低级(仿射变换)方法将FormXObject放入页面,因此无需处理仿射变换
披露:我是PDFClown的首席开发人员。更新此问题:
org.apache.pdfbox.multipdf.layeruptity
中已经有一个助手类来执行导入
将PDF页面叠加到另一个PDF上的示例:
此类是示例的一部分,并向其添加了@mkl所示的转换。是否可以使用pdfbox将其他pdf页面作为嵌入对象包含在页面中?应该可以。PDF格式允许使用所谓的表单XObject作为此类嵌入对象。虽然我没有看到一个明确的实现,但是这个过程与
PDFMergerUtility
的功能非常相似。对于该任务,您可以推荐哪些其他Java库任何通用库都应该允许您这样做,iText和PdfClown都明确支持类似的功能。@mkl对,这应该是一项相当常见的任务。查看PDFMergerUtility
,它将PDF添加为单独的页面。iText不是一个选项,因为其最新版本的许可证已更改。不过我会看看PdfClown。谢谢你指点它。它很有魅力。要添加的是,它需要存储库中的2.0.0快照。但仍无法编辑您的答案。谢谢。我添加了一个关于2.0.0使用的提示。您可能希望将您的解决方案添加到pdfbox文档中。无论如何,这已经有了一个很好的解释。这甚至可能触发它的实现……关于比较:我不是PDFBox专家。因此,比较中的一些缺点可能是由于我的编码,而不是由于PDFBox的缺陷。例如,关于资源管理,我认为我明确添加资源并非绝对必要。@mkl感谢您的注意:我更新了我的答案,以确保读者不会将其理解为客观比较。@Stefanochizzolin感谢您添加此演示。它确实有一个很好的高级API。
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;
}
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();