java pdf pdfbox

java - Cómo insertar un PDPage dentro de otro PDPage con pdfbox



(3)

¿Es posible usar pdfbox para incluir otras páginas pdf como objetos incrustados dentro de una página?

Debería ser posible. El formato PDF permite el uso de los llamados objetos de formulario para servir como tales objetos incrustados. Sin embargo, no veo una implementación explícita para eso, pero el procedimiento es lo suficientemente similar a lo que hacen PageExtractor o PDFMergerUtility .

Una prueba de concepto derivada de PageExtractor utilizando la INSTANTÁNEA actual de la versión de desarrollo PDFBox 2.0.0:

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

Este código importa la primera página de un documento fuente a un documento de destino como XObject y lo coloca dos veces en una página allí con diferentes transformaciones de escala y rotación, por ejemplo, para esta fuente

crea esto

El método auxiliar importAsXObject realmente realiza la importación se define así:

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; }

Como se mencionó anteriormente, esto es solo una prueba de concepto, los casos de esquina aún no se han tenido en cuenta.

Utilizo diferentes herramientas como el procesamiento para crear gráficos vectoriales. Estas parcelas se escriben como archivos PDF de una o varias páginas. Me gustaría incluir estas parcelas en un solo PDF tipo informe utilizando pdfbox.

Mi flujo de trabajo actual incluye estos archivos PDF como imágenes con el siguiente pseudocódigo

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

Si bien esto funciona, pierde los beneficios de los formatos de archivo vectorial, especialmente el archivo / tamaño frente a la calidad de impresión.

¿Es posible usar pdfbox para incluir otras páginas pdf como objetos incrustados dentro de una página (no se agrega como una página separada)? ¿Podría, por ejemplo, usar un PDStream? Preferiría que una solución como pdflatex sea capaz de incrustar figuras pdf en un nuevo documento pdf.

¿Qué otras bibliotecas Java puedes recomendar para esa tarea?


Como mkl sugirió apropiadamente, PDFClown encuentra entre las bibliotecas de Java que brindan soporte explícito para la incrustación de páginas (los llamados Objetos de formulario X (ver PDF Referencia 1.7, § 4.9)).

Para que pueda tener una idea de cómo funciona PDFClown, el siguiente código representa el equivalente de la solución PDFBox de mkl (NOTA: como dijo mkl más adelante, su muestra de código no estaba de ninguna manera optimizada, por lo que esta comparación puede no corresponder al valor real estado de PDFBox - los comentarios son bienvenidos para aclarar esto):

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

Al comparar este código con el equivalente de PDFBox, puede observar algunas diferencias relevantes que muestran el estilo más elegante de PDFClown (sería bueno si algún experto de PDFBox pudiera validar mis afirmaciones):

  • Conversión de página a formulario XObject : PDFClown admite de forma nativa un método dedicado (Page.toXObject ()), por lo que no es necesario realizar trabajos pesados ​​adicionales, como el método auxiliar importAsXObject ();
  • Gestión de recursos : PDFClown asigna automáticamente (y de forma transparente) los recursos de la página , por lo que no es necesario realizar llamadas explícitas como page.getResources (). AddXObject (xobject, "X");
  • Dibujo de XObject : PDFClown admite métodos de alto nivel (escala explícita, anclajes de traducción y rotación) y de bajo nivel (transformaciones afines) para colocar su FormXObject en la página, por lo que no hay necesidad de lidiar necesariamente con las transformaciones afines.

El punto es que PDFClown presenta una rica arquitectura compuesta por múltiples capas de abstracción : de acuerdo con sus requisitos, puede elegir el estilo de codificación más apropiado (ya sea para profundizar en las estructuras básicas de bajo nivel de PDF o para aprovechar su conveniente y elegante alto nivel). modelo de nivel). PDFClown le permite ajustar cada byte y resolver tareas complejas con una llamada a un método ridículamente simple, a su antojo.

DIVULGACIÓN: Soy el desarrollador principal de PDFClown.


Para actualizar esta pregunta:

Ya hay una clase auxiliar en org.apache.pdfbox.multipdf.LayerUtility para realizar la importación.

Ejemplo para mostrar la superposición de una página PDF en otro PDF: SuperimposePage .

Esta clase es parte de los ejemplos de Apache PDFBox y se le agregaron transformaciones de muestra como se muestra en @mkl.