1. Introducción
En este artículo rápido, nos centraremos en crear un documento PDF desde cero basado en la popular biblioteca iText y PdfBox.
2. Dependencias de Maven
Echemos un vistazo a las dependencias de Maven, que deben incluirse en nuestro proyecto:
com.itextpdf itextpdf 5.5.10 org.apache.pdfbox pdfbox 2.0.4
La última versión de las bibliotecas se puede encontrar aquí: iText y PdfBox.
Es necesario agregar una dependencia adicional, en caso de que nuestro archivo deba encriptarse. El paquete Bounty Castle Provider contiene implementaciones de algoritmos criptográficos y es requerido por ambas bibliotecas:
org.bouncycastle bcprov-jdk15on 1.56
La última versión de la biblioteca se puede encontrar aquí: The Bounty Castle Provider.
3. Resumen
Tanto iText como PdfBox son bibliotecas Java utilizadas para la creación / manipulación de archivos PDF. Aunque el resultado final de las bibliotecas es el mismo, operan de una manera un poco diferente. Echemos un vistazo a ellos.
4. Crear PDF en IText
4.1. Insertar texto en PDF
Echemos un vistazo a la forma en que se inserta un nuevo archivo con el texto "Hello World" en un archivo pdf.
Document document = new Document(); PdfWriter.getInstance(document, new FileOutputStream("iTextHelloWorld.pdf")); document.open(); Font font = FontFactory.getFont(FontFactory.COURIER, 16, BaseColor.BLACK); Chunk chunk = new Chunk("Hello World", font); document.add(chunk); document.close();
La creación de un pdf con el uso de la biblioteca iText se basa en la manipulación de objetos implementando la interfaz Elements en Document (en la versión 5.5.10 hay 45 de esas implementaciones).
El elemento más pequeño que se puede agregar al documento y usar se llama Chunk , que es básicamente una cadena con fuente aplicada.
Además, los fragmentos se pueden combinar con otros elementos como párrafos , secciones , etc., lo que da como resultado documentos de aspecto agradable.
4.2. Insertar imagen
La biblioteca iText proporciona una manera fácil de agregar una imagen al documento. Simplemente necesitamos crear una instancia de Imagen y agregarla al Documento .
Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI()); Document document = new Document(); PdfWriter.getInstance(document, new FileOutputStream("iTextImageExample.pdf")); document.open(); Image img = Image.getInstance(path.toAbsolutePath().toString()); document.add(img); document.close();
4.3. Insertar tabla
Podríamos tener un problema cuando quisiéramos agregar una tabla a nuestro pdf. Afortunadamente, iText proporciona dicha funcionalidad lista para usar.
Primero, lo que tenemos que hacer es crear un objeto PdfTable y en el constructor proporcionar un número de columnas para nuestra tabla. Ahora podemos simplemente agregar una nueva celda llamando
Ahora podemos simplemente agregar una nueva celda llamando al método addCell en el objeto de tabla recién creado. iText creará filas de tabla siempre que se definan todas las celdas necesarias, lo que significa es que una vez que crea una tabla con 3 columnas y le agrega 8 celdas, solo se mostrarán 2 filas con 3 celdas en cada una.
Echemos un vistazo al ejemplo:
Document document = new Document(); PdfWriter.getInstance(document, new FileOutputStream("iTextTable.pdf")); document.open(); PdfPTable table = new PdfPTable(3); addTableHeader(table); addRows(table); addCustomRows(table); document.add(table); document.close();
Creamos una nueva tabla con 3 columnas y 3 filas. La primera fila la trataremos como un encabezado de tabla con un color de fondo y un ancho de borde modificados:
private void addTableHeader(PdfPTable table) { Stream.of("column header 1", "column header 2", "column header 3") .forEach(columnTitle -> { PdfPCell header = new PdfPCell(); header.setBackgroundColor(BaseColor.LIGHT_GRAY); header.setBorderWidth(2); header.setPhrase(new Phrase(columnTitle)); table.addCell(header); }); }
La segunda fila estará compuesta por tres celdas solo con texto, sin formato adicional.
private void addRows(PdfPTable table) { table.addCell("row 1, col 1"); table.addCell("row 1, col 2"); table.addCell("row 1, col 3"); }
Podemos incluir no solo texto en las celdas, sino también imágenes. Además, cada celda puede formatearse individualmente, en el ejemplo que se presenta a continuación aplicamos ajustes de alineación horizontal y vertical:
private void addCustomRows(PdfPTable table) throws URISyntaxException, BadElementException, IOException { Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI()); Image img = Image.getInstance(path.toAbsolutePath().toString()); img.scalePercent(10); PdfPCell imageCell = new PdfPCell(img); table.addCell(imageCell); PdfPCell horizontalAlignCell = new PdfPCell(new Phrase("row 2, col 2")); horizontalAlignCell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(horizontalAlignCell); PdfPCell verticalAlignCell = new PdfPCell(new Phrase("row 2, col 3")); verticalAlignCell.setVerticalAlignment(Element.ALIGN_BOTTOM); table.addCell(verticalAlignCell); }
4.4. Cifrado de archivos
Para aplicar el permiso usando la biblioteca iText, necesitamos haber creado un documento pdf. En nuestro ejemplo, usaremos nuestro archivo iTextHelloWorld.pdf generado previamente.
Una vez que cargamos el archivo usando PdfReader , necesitamos crear un PdfStamper que se usa para aplicar contenido adicional al archivo como metadatos, cifrado, etc.
PdfReader pdfReader = new PdfReader("HelloWorld.pdf"); PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream("encryptedPdf.pdf")); pdfStamper.setEncryption( "userpass".getBytes(), ".getBytes(), 0, PdfWriter.ENCRYPTION_AES_256 ); pdfStamper.close();
En nuestro ejemplo, ciframos el archivo con dos contraseñas. La contraseña de usuario ("userpass") en la que un usuario solo tiene derechos de solo lectura sin posibilidad de imprimirla, y la contraseña de propietario ("ownerpass") que se utiliza como clave maestra que permite a una persona tener acceso completo a PDF.
Si queremos permitir que el usuario imprima pdf, en lugar de 0 (tercer parámetro de setEncryption ) podemos pasar:
PdfWriter.ALLOW_PRINTING
Por supuesto, podemos mezclar diferentes permisos como:
PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY
Tenga en cuenta que al usar iText para configurar los permisos de acceso, también estamos creando un pdf temporal que debería eliminarse y, si no, podría ser completamente accesible para cualquiera.
5. Crear PDF en PdfBox
5.1. Insertar texto en PDF
A diferencia de iText , la biblioteca PdfBox proporciona una API que se basa en la manipulación de la transmisión. No hay clases como Chunk / Paragraph, etc. La clase PDDocument es una representación Pdf en memoria donde el usuario escribe datos manipulando la clase PDPageContentStream .
Echemos un vistazo al ejemplo de código:
PDDocument document = new PDDocument(); PDPage page = new PDPage(); document.addPage(page); PDPageContentStream contentStream = new PDPageContentStream(document, page); contentStream.setFont(PDType1Font.COURIER, 12); contentStream.beginText(); contentStream.showText("Hello World"); contentStream.endText(); contentStream.close(); document.save("pdfBoxHelloWorld.pdf"); document.close();
5.2. Insertar imagen
Insertar imágenes es sencillo.
First we need to load a file and create a PDImageXObject, subsequently draw it on the document (need to provide exact x,y coordinates).
That's all:
PDDocument document = new PDDocument(); PDPage page = new PDPage(); document.addPage(page); Path path = Paths.get(ClassLoader.getSystemResource("Java_logo.png").toURI()); PDPageContentStream contentStream = new PDPageContentStream(document, page); PDImageXObject image = PDImageXObject.createFromFile(path.toAbsolutePath().toString(), document); contentStream.drawImage(image, 0, 0); contentStream.close(); document.save("pdfBoxImage.pdf"); document.close();
5.3. Inserting a Table
Unfortunately, PdfBox does not provide any out-of-box methods allowing creating tables. What we can do in such situation is to draw it manually – literally, draw each line until our drawing resembles our dreamed table.
5.4. File Encryption
PdfBox library provides a possibility to encrypt, and adjust file permission for the user. Comparing to iText, it does not require to use an already existing file, as we simply use PDDocument. Pdf file permissions are handled by AccessPermission class, where we can set if a user will be able to modify, extract content or print a file.
Subsequently, we create a StandardProtectionPolicy object which adds password-based protection to the document. We can specify two types of password. The user password, after which person will be able to open a file with applied access permissions and owner password (no limitations to the file):
PDDocument document = new PDDocument(); PDPage page = new PDPage(); document.addPage(page); AccessPermission accessPermission = new AccessPermission(); accessPermission.setCanPrint(false); accessPermission.setCanModify(false); StandardProtectionPolicy standardProtectionPolicy = new StandardProtectionPolicy("ownerpass", "userpass", accessPermission); document.protect(standardProtectionPolicy); document.save("pdfBoxEncryption.pdf"); document.close();
Nuestro ejemplo presenta una situación en la que si un usuario proporciona una contraseña de usuario, el archivo no se puede modificar ni imprimir.
6. Conclusiones
En este tutorial, discutimos formas de crear un archivo pdf en dos bibliotecas populares de Java.
Se pueden encontrar ejemplos completos en el proyecto basado en Maven en GitHub.