npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pols-pdf

v1.0.1

Published

Extiende pdfkit (TypeScript) con tablas paginadas automáticamente, celdas de texto con alineación y fuentes mixtas, e imágenes y rectángulos con bordes y radios independientes por lado.

Readme

Pols-Pdf

Clase en TypeScript/JavaScript que encapsula pdfkit para agregar primitivas de maquetado que pdfkit no ofrece de forma nativa: rectángulos con bordes y esquinas redondeadas independientes por lado, tablas con paginación automática, celdas con texto carácter-por-carácter (wrap, alineación, espaciado, fuentes mixtas) e imágenes con ajuste proportional/cover/stretch.

Instalación

npm install pols-pdf

Inicio rápido

import fs from 'fs'
import { PPdf } from 'pols-pdf'

const pdf = new PPdf({ title: 'Reporte' })

pdf.cell({ text: 'Hola mundo', height: 20 })

pdf.build().pipe(fs.createWriteStream('output.pdf'))

build() cierra el documento y devuelve el PDFDocument de pdfkit (que ya es un stream.Readable), listo para ser canalizado (pipe) a un archivo, a la respuesta HTTP, etc.


Constructor

new PPdf(params?: {
	title?: string
	page?: Partial<PPage>
	template?: () => void
	addFirstPage?: boolean
})
  • title: título del documento (metadato PDF). También accesible/editable luego vía pdf.title.
  • page: configuración de página por defecto (size, layout, margins), ver PPage.
  • template: función que se ejecuta automáticamente cada vez que se agrega una página (addPage), útil para dibujar encabezados/pies de página repetidos.
  • addFirstPage: si es false, no agrega la primera página automáticamente (por defecto true).

El cursor

PPdf mantiene internamente un cursor { left, top } que la mayoría de los métodos de dibujo leen como posición por defecto y actualizan después de dibujar. Se puede leer y mover manualmente:

pdf.getCursorLeftPosition()
pdf.getCursorTopPosition()
pdf.getBottomSpaceQuantity()   // espacio restante hasta el borde inferior de la página
pdf.getPageWidth()

pdf.setCursorLeftPosition('left')  // vuelve al margen izquierdo
pdf.setCursorLeftPosition(50)
pdf.moveCursorLeft(20)

pdf.setCursorTopPosition('top')    // vuelve al margen superior
pdf.setCursorTopPosition(100)
pdf.moveCursorTop(20)              // si autoJump (por defecto true) y se pasa del margen inferior, agrega una página nueva

Páginas

pdf.addPage({ size: 'LETTER', layout: 'landscape', margins: 30 })

margins (como todos los parámetros de tipo *BoundParams en esta librería) acepta un único número para los cuatro lados, o un objeto parcial { top?, right?, bottom?, left? }.


Rectángulos

pdf.rectangle({
	left: 20,
	top: 20,
	width: 200,
	height: 80,
	fillColor: '#eeeeee',
	border: true,                 // o { left, right, top, bottom } individuales
	radius: 8,                    // o { leftTop, rightTop, rightBottom, leftBottom }
	stroke: { width: 1, color: '#333333' }
})

rectangleTo(params) dibuja un rectángulo desde la posición actual del cursor hasta el punto { left, top } indicado (ancho/alto se calculan como la diferencia con el cursor).


Celdas de texto (cell)

pdf.cell({
	text: 'Texto de la celda',
	width: 200,
	height: 40,                 // o autojump: true si no se conoce el alto de antemano
	padding: 6,
	hAlign: 'center',
	vAlign: 'center',
	font: { size: 12, bold: true, color: '#111111' },
	border: true,
	fillColor: '#f5f5f5'
})
  • text acepta string, number, null/undefined, un objeto { chars, font? }, o un arreglo de estos últimos para mezclar fuentes/estilos dentro de una misma celda.
  • Una celda necesita o bien height (alto fijo) o bien autojump: true (el alto se calcula según el contenido y, si no entra en la página actual, el texto restante continúa automáticamente en una página nueva).
  • Si el contenido no entra en la página, cell() agrega una página nueva y continúa dibujando el resto automáticamente.

Filas y tablas (row / table)

pdf.table({
	width: 'full',              // 'full' | 'auto' | número
	border: true,
	padding: 4,
	rows: [
		{
			fillColor: '#dddddd',
			cells: [
				{ text: 'Nombre', weight: 2 },
				{ text: 'Edad', weight: 1 },
			]
		},
		{
			cells: [
				{ text: 'Ana', weight: 2 },
				{ text: '30', weight: 1 },
			]
		}
	]
})
  • Cada celda de una fila define su ancho con width (número fijo) o weight (proporción del ancho disponible restante), nunca ambos.
  • table() va maquetando fila por fila; en cuanto una fila no entra en la página actual, dibuja el buffer acumulado, agrega una página nueva y continúa con el resto — una tabla puede así abarcar varias páginas sin que el llamador tenga que ocuparse de la paginación.
  • row() expone el mismo mecanismo para dibujar una única fila suelta (fuera de una tabla).

Imágenes

pdf.image({ filePath: 'logo.png', left: 20, top: 20, width: 120 })

pdf.image({
	filePath: 'foto.jpg',
	left: 20,
	top: 20,
	width: 200,
	height: 120,
	fill: 'cover',           // 'stretch' | 'proportional' | 'cover'
	hAlign: 'center',
	vAlign: 'center'
})

Fuentes

pdf.setFont({ name: 'Helvetica', bold: true, size: 14, color: '#000000' })

Cambia la fuente activa del documento; los métodos de texto (cell, row, table) también aceptan font por llamada (y por fragmento de texto individual dentro de text), sin necesidad de llamar a setFont explícitamente.


Tipos con forma abreviada (*Params)

Los parámetros de borde, radio y márgenes/padding aceptan una forma abreviada además del objeto completo:

| Tipo | Forma corta | Forma completa | |---|---|---| | PBoundParams (padding, margins) | number (aplica a los 4 lados) | { top?, right?, bottom?, left? } | | PRadiusParams (radius) | number | { leftTop?, rightTop?, rightBottom?, leftBottom? } | | PBorderParams (border) | boolean | { leftTop?, top?, rightTop?, right?, rightBottom?, bottom?, leftBottom?, left? } | | PBorderColorParams (stroke.color) | string (color aplicado a los 4/8 lados) | { top?, rightTop?, right?, rightBottom?, bottom?, leftBottom?, left?, leftTop? } |


Convención de nombres

Todas las clases y tipos exportados llevan el prefijo P (PPdf, PCell, PRowParams, etc.), siguiendo la convención usada en los paquetes hermanos de este ecosistema: pols-date (PDate) y pols-utils (PRecord, PUtilsNumber).