@plevands/epson-thermal-printer
v0.2.0
Published
Library for Epson thermal printer integration with PDF support and React hooks
Downloads
180
Maintainers
Readme
@plevands/epson-thermal-printer
Library for Epson thermal printer integration with PDF support and React hooks.
Requirements
- Node.js 18.x or higher
- React 18.x or higher (optional, for hooks API)
- pdfjs-dist 4.x or higher (optional, for PDF processing)
- Epson thermal printer with network connectivity
Features
- ✅ Official Epson ePOS SDK integration with TypeScript support
- 🔄 Lazy loading - SDK loads automatically on first use
- 📄 PDF Processing - Intelligent margin trimming and scaling for thermal printers
- ⚛️ React Hooks - Modern hooks-based API (
useEpsonPrinter,usePrinterConfig,usePdfProcessor) - 🔧 Fully Configurable - Control PDF processing, print quality, paper width, and more
- 📦 TypeScript First - Complete type definitions included
- 🎯 Zero Config - Works out of the box with sensible defaults
- ✨ Self-contained - Epson SDK is embedded, no external dependencies to configure
Installation
Development with npm link
# In the library directory
npm install
npm run build
npm link
# In your project
npm link @plevands/epson-thermal-printerUsage in Your Projects
npm install @plevands/epson-thermal-printerNote: The Epson ePOS SDK v2.27.0 is embedded in the library. No additional setup required!
PDF Processing (Optional)
If you want to use PDF processing features (processPdfFile, usePdfProcessor), install pdfjs-dist:
npm install pdfjs-distIf you don't use PDF features, you don't need to install it. The library uses dynamic imports so pdfjs-dist is only loaded when you call PDF processing functions.
Setup (Optional)
Custom PDF.js Worker
The PDF.js worker is auto-configured to use a CDN. Only configure it if you want to use your own worker:
import { configurePdfWorker } from '@plevands/epson-thermal-printer';
// Use your own worker instead of CDN
configurePdfWorker('/assets/pdf.worker.min.mjs');Quick Start
Basic Usage (Hooks API)
import { useEpsonPrinter, usePrinterConfig } from '@plevands/epson-thermal-printer';
function MyPrintComponent() {
const { config, isConfigured } = usePrinterConfig();
const { print, isLoading, error } = useEpsonPrinter(config);
const handlePrint = async () => {
const canvas = document.querySelector('canvas') as HTMLCanvasElement;
const result = await print(canvas);
if (result.success) {
alert('Print successful!');
} else {
alert(`Print failed: ${result.message}`);
}
};
return (
<div>
{!isConfigured && <p>Please configure the printer first</p>}
<button onClick={handlePrint} disabled={isLoading || !isConfigured}>
{isLoading ? 'Printing...' : 'Print'}
</button>
{error && <p>Error: {error}</p>}
</div>
);
}Text-Only Printing with Builder (Hooks API)
import { useEpsonPrinter, usePrinterConfig } from '@plevands/epson-thermal-printer';
function TextReceipt() {
const { config, isConfigured } = usePrinterConfig({
initialConfig: { printerIP: '192.168.1.100' },
});
const { printWithBuilder, isLoading, error } = useEpsonPrinter(config, { align: 'left' });
const handlePrintText = async () => {
const result = await printWithBuilder((builder) => {
builder.addTextAlign('left');
builder.addText('TICKET #123\n');
builder.addText('Producto A x1 10.00\n');
builder.addText('TOTAL 10.00\n');
builder.addFeedLine(2);
builder.addCut('feed');
});
if (!result.success) {
console.error(result.message);
}
};
return (
<button onClick={handlePrintText} disabled={isLoading || !isConfigured}>
Imprimir texto
{error ? ` (${error})` : ''}
</button>
);
}Service API (No React)
import { EposPrintService } from '@plevands/epson-thermal-printer';
const service = new EposPrintService({
printerIP: '192.168.1.100',
printerPort: 80,
deviceId: 'local_printer',
});
// SDK loads automatically from configured path (default: /epos-2.27.0.js)
const result = await service.printCanvas(canvas);
// With HTTPS (e.g., for printers with TLS enabled)
const secureService = new EposPrintService({
printerIP: '192.168.1.100',
useHttps: true, // Uses port 443 by default when true
deviceId: 'local_printer',
});Check Printer Connection
You can verify if the printer is online before showing print options. This is useful to conditionally display UI elements or handle offline printers gracefully.
Using Hooks (React):
import { useEpsonPrinter, usePrinterConfig } from '@plevands/epson-thermal-printer';
import { useEffect, useState } from 'react';
function PrinterPanel() {
const { config, isConfigured } = usePrinterConfig();
const { checkConnection, print, isLoading, error } = useEpsonPrinter(config);
const [isOnline, setIsOnline] = useState<boolean | null>(null);
// Check connection when component mounts or config changes
useEffect(() => {
if (!isConfigured) return;
checkConnection().then(result => {
setIsOnline(result.success);
});
}, [checkConnection, isConfigured]);
if (!isConfigured) {
return <span>⚙️ Please configure the printer</span>;
}
if (isOnline === null) {
return <span>Checking printer connection...</span>;
}
if (!isOnline) {
return <span>⚠️ Printer offline: {error}</span>;
}
return (
<div>
<span>✅ Printer connected</span>
<button onClick={() => print(canvas)} disabled={isLoading}>
Print
</button>
</div>
);
}Using Service API (No React):
import { EposPrintService } from '@plevands/epson-thermal-printer';
const service = new EposPrintService({
printerIP: '192.168.1.100',
printerPort: 80,
});
// Check connection without printing anything
const result = await service.checkConnection();
if (result.success) {
console.log('Printer is online and ready!');
} else {
console.log('Printer offline:', result.message);
// result.message includes helpful details like:
// - "Printer offline"
// - "Cover open"
// - "Out of paper"
// - "Paper running low"
}| Method | Prints? | Use Case |
|--------|---------|----------|
| checkConnection() | ❌ No | Verify printer is online |
| testConnection() | ✅ Yes | Print a small test receipt |
With PDF Processing
import {
useEpsonPrinter,
usePdfProcessor,
usePrinterConfig
} from '@plevands/epson-thermal-printer';
function PdfPrinter() {
const { config, isConfigured } = usePrinterConfig();
const { processFile } = usePdfProcessor({
enabled: true,
trimMargins: { top: 10, bottom: 10, left: 5, right: 5 },
targetWidth: 576, // 80mm paper
monochromeThreshold: 160,
});
const { printPages } = useEpsonPrinter(config);
const handlePrint = async (file: File) => {
// Process PDF with margin trimming and scaling
const pages = await processFile(file);
// Print all processed pages
const result = await printPages(
pages.map(p => p.canvas),
{ pageSelection: 'all' }
);
};
return <div>{/* Your UI */}</div>;
}Configuration
PDF Processing Options
interface PdfProcessingConfig {
enabled: boolean; // Enable/disable processing
trimMargins?: {
top?: number; // Default: 8px
bottom?: number; // Default: 8px
left?: number; // Default: 8px
right?: number; // Default: 8px
};
targetWidth?: number; // Default: 576 (80mm paper)
scale?: number; // Render scale, default: 3
monochromeThreshold?: number; // 0-255, default: 160
}Paper Width Reference
| Paper Size | Width (pixels) | targetWidth value |
|------------|----------------|---------------------|
| 80mm | 576px | 576 (default) |
| 58mm | 384px | 384 |
Print Options
interface PrintOptions {
halftone?: 0 | 1 | 2; // 0=DITHER, 1=ERROR_DIFFUSION, 2=THRESHOLD
brightness?: number; // 0.1 to 10.0, default 1.0
mode?: 'mono' | 'gray16';
cut?: boolean;
align?: 'left' | 'center' | 'right';
}Printer Configuration
interface EpsonPrinterConfig {
printerIP: string; // Required
printerPort?: number; // Default: 80 (or 443 if useHttps is true)
deviceId?: string; // Default: 'local_printer'
timeout?: number; // Default: 60000ms
useHttps?: boolean; // Use HTTPS instead of HTTP (default: false)
}API Reference
Hooks
useEpsonPrinter(config, options?)
Main hook for printer operations with automatic SDK loading.
Parameters:
config-EpsonPrinterConfig | null— printer configuration (passnullor unconfigured hook value; operations will returnNOT_CONFIGUREDerror)options?-PrintOptions— default print options
Returns:
print(canvas)- Print a single canvasprintPages(canvases, options?)- Print multiple pagesprintWithBuilder(builder => ...)- Print custom ePOSBuilder commands (ideal for text receipts)checkConnection()- Check printer connection without printingtestConnection()- Test printer connectionisLoading- Loading stateerror- Error message if anysdkStatus- SDK loading status
usePrinterConfig(options?)
Manages printer configuration with localStorage persistence.
Without arguments, config starts as null until the user calls updateConfig. Pass initialConfig to provide defaults for new users. Pass storageKey to use a custom localStorage key — useful when managing multiple printer configurations (e.g. one per network).
Options (UsePrinterConfigOptions):
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| initialConfig | EpsonPrinterConfig | undefined | Defaults for new users. localStorage values take priority for returning users. |
| storageKey | string | 'epson-printer-config' | localStorage key for this configuration instance. |
// No defaults — config is null until user configures
const { config, isConfigured } = usePrinterConfig();
// With defaults — config starts pre-filled
const { config, isConfigured } = usePrinterConfig({
initialConfig: { printerIP: '10.0.0.50' },
});
// Multiple configs for different networks
const office = usePrinterConfig({ storageKey: 'printer-office' });
const warehouse = usePrinterConfig({ storageKey: 'printer-warehouse' });Returns:
config- Current configuration (EpsonPrinterConfig | null)updateConfig(partial)- Update configuration (persists to localStorage)resetConfig()- Reset to initial value (initialConfigif provided, otherwisenull) and clear localStorageisConfigured-truewhen config is not null and has a valid printer IP
usePdfProcessor(config?)
Process PDF files with configurable options.
Returns:
processFile(file)- Process PDF fileisProcessing- Processing stateerror- Error message if any
Services
EposPrintService
Core service class for printing operations.
const service = new EposPrintService(config, options);
// Methods
await service.printCanvas(canvas);
await service.printWithBuilder((builder) => {
builder.addTextAlign('center');
builder.addText('Hello World!\n');
builder.addFeedLine(3);
builder.addCut('feed');
});
await service.printPages(canvases, { header: 'Header Text' });
await service.testConnection(); // Prints a test receipt
await service.printTestPage(); // Prints a detailed test pageSDK Loader Functions
import {
loadEpsonSDK,
isEpsonSDKLoaded,
initializeEpsonSDK,
getEpsonSDK,
checkEpsonSDKStatus,
} from '@plevands/epson-thermal-printer';
// Check if loaded
const loaded = isEpsonSDKLoaded();
// Check detailed SDK status
const status = checkEpsonSDKStatus();
// Returns: { loaded: boolean, loading: boolean, error: string | null, classes: string[] }
// Get SDK instance (after loading)
const sdk = getEpsonSDK();
// Manual initialization (optional)
const result = await initializeEpsonSDK();
// Note: SDK loads automatically on first print - no manual call needed!PDF Processing Functions
import {
configurePdfWorker,
isPdfWorkerConfigured,
PDFJS_CDN_WORKER_URL,
processPdfFile,
processPdfPage,
} from '@plevands/epson-thermal-printer';
// Configure PDF.js worker (optional but recommended)
configurePdfWorker(PDFJS_CDN_WORKER_URL);
// Check if worker is configured
const configured = isPdfWorkerConfigured();
// Process a PDF file
const pages = await processPdfFile(file, {
targetWidth: 576,
trimMargins: { top: 10, bottom: 10 },
});Logging Configuration
By default, only errors are logged to the console. You can enable debug logs or intercept all logs with a custom handler:
import { configureLogger } from '@plevands/epson-thermal-printer';
// Enable all logs (debug, warn, error) in console
configureLogger({ enabled: true });
// Intercept all logs with custom handler
configureLogger({
enabled: false, // Don't show debug/warn in console (errors always shown)
onLog: (entry) => {
// entry: { level: 'debug' | 'warn' | 'error', message: string, args?: unknown[] }
myLoggingService.log(entry.level, entry.message, entry.args);
},
});
// Combine both: show in console AND send to custom handler
configureLogger({
enabled: true,
onLog: (entry) => sendToAnalytics(entry),
});Running the Demo App
This repository includes a demo application to test the library:
# Clone the repository
git clone https://github.com/plevands/epson-printer.git
cd epson-printer
# Install dependencies
npm install
# Start the development server
npm run dev
# Open in browser: http://localhost:5123The demo app demonstrates:
- 🖨️ Printer configuration
- 📄 PDF file upload and preview
- 🎨 Real-time PDF processing visualization
- ⚙️ Print controls with customizable options
Development Workflow with npm link
In the Library
# Make changes to the library
npm run build # Build once
# OR
npm run dev:lib # Watch mode - rebuilds on changesIn Your Project
# Link the library (once)
npm link @plevands/epson-thermal-printer
# Your project will use the local version
# Changes to the library reflect immediately after rebuildUnlinking
# In your project
npm unlink @plevands/epson-thermal-printer
# In the library
npm unlinkNetwork Requirements
CORS Configuration
The printer must allow CORS requests from your application domain. Configure your printer's web interface:
- Access printer at
http://[PRINTER_IP] - Navigate to Network > CORS settings
- Add your application origin (e.g.,
http://localhost:5173)
Firewall
Ensure port 80 (or custom port) is accessible on the printer's IP address.
Technical Notes
SDK Inheritance Pattern
The Epson ePOS SDK uses JavaScript prototypal inheritance where ePOSPrint extends ePOSBuilder via ePOSPrint.prototype = new ePOSBuilder(). This pattern has an important implication:
Problem: When calling builder methods directly on ePOSPrint instance (e.g., printer.addText()), the commands accumulate in a shared prototype message property, not an instance property. When send() is called internally, it creates a new empty ePOSBuilder instead of using the accumulated commands.
Solution: This library handles this by using separate ePOSBuilder instances:
// ✅ Correct pattern (used internally by this library)
const builder = new epson.ePOSBuilder();
builder.addText('Hello');
builder.addCut(builder.CUT_FEED);
const xml = builder.toString();
const printer = new epson.ePOSPrint(printerUrl);
printer.send(xml); // Pass XML explicitlyIf you're extending this library or using the raw SDK, always follow this pattern to avoid empty print requests.
Troubleshooting
SDK Not Loading
The SDK loads automatically on first print. If you see errors:
- Check console for loading errors
- Verify
public/epos-2.27.0.jsexists in your build - Try manual initialization:
import { initializeEpsonSDK } from '@plevands/epson-thermal-printer'; await initializeEpsonSDK();
Connection Failed
- Verify printer IP address is correct
- Check CORS configuration on printer
- Ensure printer is on same network
- Test connection:
const { testConnection } = useEpsonPrinter(config); await testConnection();
Print Quality Issues
Adjust print options:
const { print } = useEpsonPrinter(config, {
halftone: 1, // Try different values (0, 1, 2)
brightness: 1.2, // Increase for lighter prints
mode: 'mono', // Or 'gray16' for grayscale
});PDF Processing Issues
Fine-tune processing config:
const { processFile } = usePdfProcessor({
enabled: true,
trimMargins: { top: 0, bottom: 0, left: 0, right: 0 }, // Disable trimming
monochromeThreshold: 180, // Higher = more white
});Examples
See the included demo app in this repository for complete examples of all features.
npm run dev # Start demo app
npm run build # Build library for production
npm run lint # Run ESLintBrowser Support
| Browser | Supported | |---------|-----------| | Chrome | ✅ 90+ | | Firefox | ✅ 88+ | | Safari | ✅ 14+ | | Edge | ✅ 90+ |
Note: Requires modern browser with ES2020+ and Canvas API support.
License
MIT © Colegio Plevand's
Contributing
Contributions welcome! Please feel free to submit issues and pull requests.
