kashipu-printer
v2.0.0
Published
Thermal printer SDK for ESC/POS printers. Print text, QR codes, images, and barcodes via Bluetooth or USB.
Maintainers
Readme
kashipu-printer
SDK para impresoras térmicas ESC/POS. Imprime texto con formato, códigos QR, imágenes y códigos de barras via Bluetooth o USB desde cualquier proyecto TypeScript/JavaScript.
Instalación
npm install kashipu-printerInicio rápido
import { ThermalPrinter, ReceiptBuilder, UsbAdapter } from 'kashipu-printer';
// 1. Crear impresora con un adaptador
const printer = new ThermalPrinter({
adapter: new UsbAdapter('http://localhost:9100'),
columns: 32, // 32 para 48mm, 42 para 58mm, 48 para 80mm
codepage: 'windows1252'
});
// 2. Conectar
await printer.connect();
// 3. Construir recibo
const receipt = new ReceiptBuilder()
.text('MI NEGOCIO', { align: 'center', bold: true, size: 'double' })
.text('NIT: 800.123.456-1', { align: 'center' })
.separator()
.keyValue('Placa', 'ABC-123')
.keyValue('Fecha', '2026-03-10')
.separator()
.keyValue('TOTAL', '$11.900', { bold: true })
.spacer()
.qrcode('https://miweb.com/ticket/123')
.text('Gracias por su visita', { align: 'center' })
.build();
// 4. Imprimir
await printer.print(receipt);Adaptadores
La librería usa el patrón adaptador para soportar diferentes conexiones. Escoge el que necesites:
UsbAdapter (PC / Windows)
Envía datos ESC/POS a una impresora USB local a través de un servidor HTTP incluido.
import { UsbAdapter } from 'kashipu-printer';
const adapter = new UsbAdapter('http://127.0.0.1:9100');Requisito: Ejecutar el print server (ver sección Print Server).
BluetoothAdapter (Mobile / Cordova)
Para apps móviles con Cordova/Capacitor. Requiere instalar el plugin Bluetooth Serial:
npm install @awesome-cordova-plugins/bluetooth-serial cordova-plugin-bluetooth-serialimport { BluetoothAdapter } from 'kashipu-printer';
import { BluetoothSerial } from '@awesome-cordova-plugins/bluetooth-serial/ngx';
const bluetoothSerial = new BluetoothSerial();
const adapter = new BluetoothAdapter(bluetoothSerial);MockAdapter (Testing / Desarrollo)
Simula una impresora en consola. No requiere hardware.
import { MockAdapter } from 'kashipu-printer';
const adapter = new MockAdapter();
// Los datos enviados se loguean en console.logAdaptador personalizado
Puedes crear tu propio adaptador implementando la interfaz PrinterAdapter:
import { PrinterAdapter, PrinterDevice } from 'kashipu-printer';
class MiAdapter implements PrinterAdapter {
async scan(): Promise<PrinterDevice[]> { /* ... */ }
async connect(address: string): Promise<boolean> { /* ... */ }
async disconnect(): Promise<boolean> { /* ... */ }
async isConnected(): Promise<boolean> { /* ... */ }
async write(data: Uint8Array): Promise<boolean> { /* ... */ }
}API de ThermalPrinter
const printer = new ThermalPrinter(options);Constructor
| Opción | Tipo | Default | Descripción |
|--------|------|---------|-------------|
| adapter | PrinterAdapter | requerido | Adaptador de conexión |
| columns | number | 32 | Caracteres por línea |
| codepage | string | 'windows1252' | Codificación de caracteres |
| language | 'esc-pos' \| 'star-prnt' | 'esc-pos' | Variante del lenguaje |
| codepageMapping | 'epson' \| 'star' \| 'bixolon' | 'epson' | Mapeo de codepage |
Métodos
| Método | Retorno | Descripción |
|--------|---------|-------------|
| scan() | Promise<PrinterDevice[]> | Buscar impresoras disponibles |
| connect(address?) | Promise<boolean> | Conectar a la impresora |
| disconnect() | Promise<boolean> | Desconectar |
| isConnected() | Promise<boolean> | Verificar conexión |
| print(receipt) | Promise<boolean> | Imprimir un ReceiptData |
| printText(text) | Promise<boolean> | Imprimir texto plano |
| printRaw(data) | Promise<boolean> | Enviar bytes ESC/POS crudos |
| preview(receipt) | string | Generar preview HTML del recibo |
| getConfig() | PrinterConfig | Obtener configuración actual |
ReceiptBuilder
API fluente para construir recibos sección por sección:
const receipt = new ReceiptBuilder()
// Texto con opciones de estilo
.text('TÍTULO', { align: 'center', bold: true, size: 'double' })
.text('Subtítulo', { align: 'center' })
.text('Subrayado', { underline: true })
.text('Doble subrayado', { underline: 2 })
.text('Itálica', { italic: true })
.text(' Invertido ', { invert: true })
.text('Font B pequeña', { font: 'B' })
.text('Ancho 3x', { width: 3 })
.text('Alto 2x', { height: 2 })
// Par clave-valor
.keyValue('Producto', 'Café')
.keyValue('Total', '$5.000', { bold: true })
// Línea separadora (caracter por defecto: '-')
.separator()
.separator('=')
// Línea horizontal nativa
.rule() // simple
.rule('double') // doble
// Tabla con columnas
.table(
[{ width: 16, align: 'left' }, { width: 10, align: 'right' }],
[['Producto', 'Precio'], ['Café', '$3.000']]
)
// Caja con bordes
.box('TOTAL: $5.000', { style: 'double' })
// Líneas vacías
.spacer() // 1 línea
.spacer(3) // 3 líneas
// Código QR (tamaño 1-8, default 6)
.qrcode('https://ejemplo.com', 6)
// Código de barras
.barcode('7501234567890', 'ean13', 60)
// PDF417 (facturación electrónica)
.pdf417('Datos de factura', { width: 3, height: 3 })
// Imagen bitmap (requiere ImageData: { data, width, height })
// Algoritmos: 'atkinson', 'floydsteinberg', 'bayer', 'threshold'
.image(imageData, 'atkinson', 128)
// Corte de papel
.cut('full') // o 'partial'
// Construir
.build();Opciones de texto
| Opción | Valores | Default |
|--------|---------|---------|
| align | 'left', 'center', 'right' | 'left' |
| bold | boolean | false |
| underline | boolean \| 2 | false |
| italic | boolean | false |
| invert | boolean (blanco sobre negro) | false |
| font | 'A' (normal), 'B' (pequeña) | 'A' |
| size | 'normal', 'double' | 'normal' |
| width | 1-8 (escala horizontal) | 1 |
| height | 1-8 (escala vertical) | 1 |
Algoritmos de dithering para imágenes
| Algoritmo | Descripción |
|-----------|-------------|
| threshold | Binario simple (rápido, menos detalle) |
| bayer | Patrón ordenado 4x4 (líneas diagonales) |
| floydsteinberg | Difusión de error (alta calidad, gradientes naturales) |
| atkinson | Difusión de error suave (mejor para detalles finos) |
Preview HTML
Genera un string HTML que simula visualmente el recibo térmico. Útil para previsualizaciones en la app:
const html = printer.preview(receipt);
document.getElementById('preview').innerHTML = html;Print Server (USB en Windows)
Para imprimir desde el navegador a una impresora USB en Windows, se necesita el print server incluido. Este recibe datos ESC/POS via HTTP y los envía a la impresora usando la API Win32 winspool.drv.
Requisitos previos
- Tener la impresora instalada en Windows (Panel de control > Impresoras)
- Conocer el nombre exacto de la impresora (ej:
"Generic / Text Only")
Iniciar el servidor
# Opción 1: Con npx (después de instalar kashipu-printer)
npx kashipu-print-server
npx kashipu-print-server "Mi Impresora"
# Opción 2: Directamente con node
node node_modules/kashipu-printer/tools/print-server/server.js "Mi Impresora"
# Opción 3: Desde el repo clonado
npm run print-serverVariables de entorno
| Variable | Default | Descripción |
|----------|---------|-------------|
| KASHIPU_PORT | 9100 | Puerto del servidor |
| KASHIPU_PRINTER | Generic / Text Only | Nombre de la impresora |
Endpoints
| Método | Ruta | Descripción |
|--------|------|-------------|
| GET | /status | Estado de la impresora: { connected, printer, port } |
| POST | /print | Enviar bytes ESC/POS (body: application/octet-stream) |
Probar conexión
# Verificar que la impresora está conectada
curl http://127.0.0.1:9100/statusRespuesta esperada:
{ "connected": true, "printer": "Generic / Text Only", "port": "USB001" }Impresoras probadas
| Impresora | Conexión | Columnas | Codepage | Estado | |-----------|----------|----------|----------|--------| | GEZHI Mini (48mm) | USB | 32 | windows1252 | Funciona |
Configuración por tamaño de papel
| Papel | Columnas | |-------|----------| | 48mm | 32 | | 58mm | 42 | | 80mm | 48 |
Codepages comunes
| Codepage | Uso |
|----------|-----|
| windows1252 | Español, Francés, Portugués (caracteres acentuados) |
| cp850 | DOS Latin-1 |
| cp437 | ASCII extendido original |
Ejemplos
Ticket de entrada (parqueadero)
const ticket = new ReceiptBuilder()
.text('PARQUEADERO CENTRAL', { align: 'center', bold: true, size: 'double' })
.spacer()
.text('TICKET DE ENTRADA', { align: 'center' })
.spacer()
.keyValue('Placa', 'ABC-123')
.keyValue('Tipo', 'CARRO')
.keyValue('Fecha', '10/03/2026')
.keyValue('Hora', '14:30')
.spacer()
.text('Conserve su ticket', { align: 'center' })
.build();
await printer.print(ticket);Factura de venta
const factura = new ReceiptBuilder()
.text('RESTAURANTE DOÑA ROSA', { align: 'center', bold: true, size: 'double' })
.text('NIT: 900.456.789-1', { align: 'center' })
.text('Calle 45 #12-30', { align: 'center' })
.separator()
.keyValue('Mesa', '5')
.keyValue('Mesero', 'Carlos')
.separator()
.keyValue('2x Bandeja Paisa', '$36.000')
.keyValue('1x Jugo Natural', '$6.000')
.keyValue('1x Postre', '$8.000')
.separator('=')
.keyValue('SUBTOTAL', '$50.000')
.keyValue('IVA 19%', '$9.500')
.keyValue('TOTAL', '$59.500', { bold: true })
.spacer()
.text('EFECTIVO', { align: 'center' })
.spacer()
.qrcode('https://miweb.com/factura/001')
.text('Gracias por su visita', { align: 'center' })
.build();
await printer.print(factura);Texto simple
await printer.printText('Hola mundo desde kashipu-printer!');Imprimir imagen
// Desde un Canvas (navegador)
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = 'logo.png';
img.onload = async () => {
canvas.width = img.width;
// Altura debe ser múltiplo de 8
canvas.height = Math.ceil(img.height / 8) * 8;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const receipt = new ReceiptBuilder()
.image(imageData, 'atkinson')
.build();
await printer.print(receipt);
};Estructura del proyecto
kashipu-printer/
├── src/
│ ├── index.ts # Barrel export
│ ├── printer.ts # ThermalPrinter (clase principal)
│ ├── models/
│ │ ├── config.ts # PrinterConfig, PrinterDevice
│ │ └── receipt.ts # ReceiptData, secciones
│ ├── builder/
│ │ ├── receipt-builder.ts # API fluent para construir recibos
│ │ ├── esc-pos-builder.ts # ReceiptData → Uint8Array
│ │ └── html-preview-builder.ts # ReceiptData → HTML string
│ └── adapters/
│ ├── adapter.ts # PrinterAdapter interface
│ ├── usb.adapter.ts # HTTP print server
│ ├── bluetooth.adapter.ts # Cordova Bluetooth Serial
│ └── mock.adapter.ts # Console mock
└── tools/
└── print-server/
├── server.js # HTTP → Win32 RAW print
└── raw-print.ps1 # PowerShell winspool.drvLicencia
MIT
