Generación de archivos PDF en Node.js con PDFKit

G

 

Introducción

El formato PDF es uno de los formatos de documentos más comunes para transferir información. En aplicaciones web dinámicas, es posible que necesite exportar datos a un documento y PDF suele ser una opción popular. En este artículo, discutiremos cómo generar archivos PDF en NodeJS usando el paquete NPM pdfkit.

PDFKit es una biblioteca de generación de PDF de JavaScript para Node.js que proporciona una manera fácil de crear documentos PDF imprimibles de varias páginas.

Introducción a PDFKit

Creemos un directorio de proyecto, cd en él e inicializar el proyecto Node con la configuración predeterminada:

$ mkdir pdfkit-project
$ cd pdfkit-project
$ npm init -y

Entonces vamos install pdfkit:

$ npm install pdfkit

Para usar el módulo en el proyecto, lo importaremos a través de require():

const PDFDocument = require('pdfkit');

Crear un documento PDF usando PDFKit

Para crear un documento PDF, necesitaremos importar el fs (sistema de archivos) módulo también. Canalizaremos el contenido de nuestro archivo PDF en un fsflujo de escritura para guardarlo. Echemos un vistazo a cómo hacer eso:

const PDFDocument = require('pdfkit');
const fs = require('fs');

let pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('SampleDocument.pdf'));
pdfDoc.text("My Sample PDF Document");
pdfDoc.end();

Primero, importamos los módulos requeridos, luego de lo cual, instanciamos el PDFDocument. Esta instancia es una secuencia legible. Estaremos canalizando esa secuencia a una secuencia de escritura para guardar el archivo.

Si no está familiarizado con el funcionamiento de las transmisiones, consulte nuestra Introducción a las transmisiones de Node.js.

Estamos usando el pipe() función para hacer esto y guardar el resultado SampleDocument.pdf en nuestro directorio raíz. Una vez creado, podemos agregarle contenido, a través del text función. Por supuesto que queremos end() la corriente al final.

Cuando ejecutamos el código, un archivo PDF llamado SampleDocument.pdf se crea en la carpeta raíz de nuestro proyecto:

$ node index.js

Nota: Antes de intentar sobrescribir un archivo PDF existente, debe ser gratuito. Es decir, todas las Windows con ese archivo PDF deben cerrarse o el programa arrojará un error.

Formateo de texto en archivo PDF

Por supuesto, pdfkit nos permite hacer mucho más que agregar texto sin formato a un documento. Echemos un vistazo a algunas de las características que ofrece.

Colocación de texto

Por defecto, el pdfkit El módulo realiza un seguimiento de dónde se debe agregar el texto al documento, esencialmente imprime cada llamada al text() función en una nueva línea.

Puede cambiar dónde se imprime el texto dentro de la página actual, agregando las coordenadas xey de la ubicación donde desea que el texto se coloque como argumentos a la text() función.

Por ejemplo:

pdfDoc.text("Text positioned at (200,200)", 200, 200);

Esto es útil porque le permite ajustar la posición del texto, especialmente porque los documentos PDF tienen un aspecto universal independientemente de la máquina / sistema operativo en el que estén abiertos. Esto también le permitiría, por ejemplo, imprimir texto sobre otro texto:

const PDFDocument = require('pdfkit');
const fs = require('fs');

var pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('SampleDocument.pdf'));

pdfDoc.text("From Mon-Sat we will have a 10% discount on selected items!", 150, 150);
pdfDoc
    .fillColor('red')
    .fontSize(17)
    .text("20%", 305, 150);

pdfDoc.end();

Ejecutar este código nos daría:

Ajuste y alineación de texto

los pdfkit módulo envuelve automáticamente las líneas para que quepan entre los márgenes, o en el width proporcionado (al escribir texto en columnas). En otras palabras, el lineBreak la opción es true por defecto. Puedes cambiarlo a false al llamar al text() función:

pdfDoc.text("very long text ".repeat(20), { lineBreak : false });

Las nuevas páginas también se agregan automáticamente según sea necesario, es decir, tan pronto como el contenido que desea agregar no encaja en la página actual en su totalidad. Sin embargo, también puede pasar a la página siguiente antes de completar la anterior simplemente llamando a:

pdfDoc.addPage();

En cuanto a la alineación, pdfkit nos proporciona las opciones habituales – left (defecto), right, center y justify. Tenga en cuenta que establecer una alineación específica con lineBreak ajustado a false no funcionará, incluso si el texto cabe en una línea.

Tal como lineBreak, la align El parámetro se establece pasando un objeto que contiene pares clave-valor al text() función. Veamos algunos ejemplos de alineación:

const PDFDocument = require('pdfkit');
const fs = require('fs');

var pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('text_alignment.pdf'));

pdfDoc.text("This text is left aligned", { align: 'left'})
pdfDoc.text("This text is at the center", { align: 'center'})
pdfDoc.text("This text is right aligned", { align: 'right'})
pdfDoc.text("This text needs to be slightly longer so that we can see that justification actually works as intended", { align: 'justify'})

pdfDoc.end();

Ejecutar el código anterior nos daría un PDF con este aspecto:

Estilo de texto

los pdfkit El módulo también proporciona opciones que se pueden utilizar para aplicar estilo al texto en sus documentos PDF. Echaremos un vistazo a algunas de las opciones de estilo más importantes, puede encontrar la lista completa de opciones en el Guía PDF.

Podemos pasar diferentes opciones como pares clave-valor al text() función, y también encadenar varias otras funciones antes de llamar text() en absoluto.

Una cosa muy importante a tener en cuenta es que las funciones encadenadas, como fillColor() (y después font(), fontSize(), etc.) afectará a todo el texto después de esa llamada:

const PDFDocument = require('pdfkit');
const fs = require('fs');

var pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('text_styling.pdf'));

pdfDoc
    .fillColor('blue')
    .text("This is a link", { link: 'https://pdfkit.org/docs/guide.pdf', underline: true });
pdfDoc
    .fillColor('black')
    .text("This text is underlined", { underline: true });
pdfDoc.text("This text is italicized", { oblique: true });
pdfDoc.text("This text is striked-through", { strike: true });

pdfDoc.end();

La ejecución de este código generará un archivo PDF con el siguiente contenido:

Cambiar estilos en el medio de un párrafo es un poco más complicado, ya que encadenar múltiples text() functions agrega una nueva línea después de cada una de forma predeterminada. Podemos evitar esto configurando el lineBreak opción de la primera text() llamar a false:

const PDFDocument = require('pdfkit');
const fs = require('fs');

var pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('text_styling2.pdf'));

pdfDoc
    .fillColor('blue')
    .text("This text is blue and italicized", {oblique : true, lineBreak : false})
    .fillColor('red')
    .text(" This text is red");

pdfDoc.end();

Lo que nos daría el resultado deseado:

Crear listas

Para agregar una lista de elementos en su documento PDF, el PDFDocument instancia tiene un list() función que toma una matriz de elementos de cadena (o matrices anidadas de cadenas) y las muestra como una lista de viñetas:

const PDFDocument = require('pdfkit');
const fs = require('fs');

let pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('lists.pdf'));

let myArrayOfItems = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];

pdfDoc.list(myArrayOfItems);
// Move down a bit to provide space between lists
pdfDoc.moveDown(0.5);

let innerList = ['Nested Item 1', 'Nested Item 2'];
let nestedArrayOfItems = ['Example of a nested list', innerList];

pdfDoc.list(nestedArrayOfItems);

pdfDoc.end();

Lo que nos da:

Fuentes

PDFKit viene con 14 fuentes estándar que se pueden usar en documentos PDF. Cualquiera de estas fuentes se puede pasar al font() función de la PDFDocument clase, y encadenado con text():

pdfDoc.font('Times-Roman').text('A text in Times Roman')

También puede agregar fuentes adicionales pasando la ruta al archivo de fuentes como argumento a la font() función, así como el nombre de la fuente específica que desea en caso de que el archivo tenga una colección de fuentes. Alternativamente, puede darle un nombre a la nueva fuente para que se pueda acceder a ella por ese nombre en lugar de la ruta del archivo:

pdfDoc.registerFont('Name of the font', '/file_path', 'specific_font_name_in_case_of_a_collection')

Llamadas a font() se puede encadenar con otras funciones, al igual que en el fillColor() ejemplo.

También puede establecer el tamaño de fuente mediante el fontSize() función. Echemos un vistazo a algunos ejemplos:

const PDFDocument = require('pdfkit');
const fs = require('fs');

let pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('fonts.pdf'));

pdfDoc.font('ZapfDingbats').text('This is a symbolic font.');
pdfDoc.font('Times-Roman').fontSize(25).fillColor('blue').text('You can set a color for any font');
pdfDoc.font('Courier').fontSize(5).fillColor('black').text('Some text to demonstrate.');

pdfDoc.end();

Ejecutar esto nos daría el siguiente PDF como resultado:

Agregar imágenes

Otra cosa común que quizás desee agregar a sus archivos PDF son las imágenes. Puedes llamar al image() función en la instancia del documento y pasar la ruta o el URI de la imagen que desea incluir.

También puede establecer opciones como el ancho, alto, alineación horizontal y vertical de la imagen pasando un objeto que contenga pares clave-valor como argumento a la image() función. De forma predeterminada, las imágenes se cargan en su tamaño original.

Si configura el width y height – la imagen se estirará para ajustarse a los parámetros especificados. Si se omite uno de estos, la imagen se escala proporcionalmente al parámetro proporcionado:

const PDFDocument = require('pdfkit');
const fs = require('fs');

let pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('images.pdf'));

pdfDoc.text('By default, the image is loaded in its full size:')
pdfDoc.image('raspberries.jpg');

pdfDoc.moveDown(0.5)
pdfDoc.text('Scaled to fit width and height')
pdfDoc.image('raspberries.jpg', {width: 150, height: 150});

pdfDoc.moveDown(0.5)
pdfDoc.text('Scaled to fit width')
pdfDoc.image('raspberries.jpg', {width: 150});

pdfDoc.end();

Ejecutar este código nos daría:

También puede escalar la imagen dando un scale factor. Además, puede dar un fit o cover matriz, donde la imagen se escalará para ajustarse al rectángulo provisto o para cubrirlo, respectivamente. Si proporciona un fit o cover matriz, también puede establecer la alineación horizontal (align) y la alineación vertical (valign):

const PDFDocument = require('pdfkit');
const fs = require('fs');

let pdfDoc = new PDFDocument;
pdfDoc.pipe(fs.createWriteStream('images.pdf'));

pdfDoc.text('Scaled by a factor, keeps the original proportions:')
pdfDoc.image('raspberries.jpg', {scale: 0.75});

pdfDoc.moveDown(0.5)
pdfDoc.text('Fit with horizontal alignment:')
pdfDoc.image('raspberries.jpg', {fit: [400, 150], align: 'center'});

pdfDoc.end();

Esto nos daría:

Conclusión

En este artículo hemos visto cómo generar archivos PDF en Node.js usando PDFKit. Hemos explorado algunas de las opciones disponibles para formatear texto y cómo agregar imágenes a nuestros archivos. La biblioteca tiene una extensa documentación que cubre mucho más sobre la creación de archivos PDF en aplicaciones Node.js.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con tus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad