我使用不同的工具,如处理来创建矢量图。这些图表是单页或多页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?我更喜欢像pdflatex这样的解决方案能够将pdf数字嵌入到新的pdf文档中。
您可以为该任务推荐哪些其他Java库?
答案 0 :(得分:4)
是否可以使用pdfbox将其他pdf页面包含在页面中的嵌入对象
中
应该可以。 PDF格式允许使用所谓的表单xobjects作为这样的嵌入对象。但是,我没有看到明确的实现,但该过程与PageExtractor
或PDFMergerUtility
的过程类似。
使用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导入目标文档,并将其两次放到具有不同缩放和旋转变换的页面上,例如:对于这个来源
它创建了这个
实际执行导入的辅助方法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;
}
如上所述,这只是一个概念证据,尚未考虑角落案件。
答案 1 :(得分:3)
更新此问题:
org.apache.pdfbox.multipdf.LayerUtility
中已有一个辅助类来进行导入。
显示将PDF页面叠加到另一个PDF上的示例: SuperimposePage 。
此类是Apache PDFBox Examples的一部分,并且已添加@mkl所示的示例转换。
答案 2 :(得分:2)
正如mkl所说, PDFClown 是提供显式支持页面嵌入的Java库(所谓的Form XObjects)(参见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专家可以验证我的断言,那将会很不错):
重点是 PDFClown具有由多个抽象层组成的丰富架构:根据您的要求,您可以选择最合适的编码风格(深入研究PDF的低级基础)结构或利用其方便和优雅的高级模型)。 PDFClown让您可以随意调整每个字节,并通过一个非常简单的方法调用来解决复杂的任务。
披露:我是PDFClown的首席开发人员。