import { PrinterType } from "./printer-type"; import { EpsonConfig } from "./epson-config"; export class Epson implements PrinterType { public config = EpsonConfig; private buffer: Buffer | null = null; code128(): Buffer { throw new Error("code128 not implemented for Epson"); } // ------------------------------ Append ------------------------------ append(appendBuffer: Buffer) { if (this.buffer) { this.buffer = Buffer.concat([this.buffer, appendBuffer]); } else { this.buffer = appendBuffer; } } // ------------------------------ Beep ------------------------------ beep() { return this.config.BEEP; } // ------------------------------ Set text size ------------------------------ setTextSize(height: number, width: number): Buffer { this.buffer = null; if (height > 7 || height < 0) throw new Error("setTextSize: Height must be between 0 and 7"); if (width > 7 || width < 0) throw new Error("setTextSize: Width must be between 0 and 7"); let x = Buffer.from(height + "" + width, "hex"); this.append(Buffer.from([0x1d, 0x21])); this.append(x); return this.buffer!; } // ------------------------------ QR ------------------------------ printQR( str: string, settings?: { cellSize?: number; correction?: "L" | "M" | "Q" | "H"; model?: number; } ): Buffer { this.buffer = null; settings = settings || {}; // [Name] Select the QR code model // [Code] 1D 28 6B 04 00 31 41 n1 n2 // n1 // [49 x31, model 1] // [50 x32, model 2] // [51 x33, micro qr code] // n2 = 0 // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=140 if (settings.model) { if (settings.model === 1) this.append(this.config.QRCODE_MODEL1); else if (settings.model === 3) this.append(this.config.QRCODE_MODEL3); else this.append(this.config.QRCODE_MODEL2); } else { this.append(this.config.QRCODE_MODEL2); } // [Name]: Set the size of module // 1D 28 6B 03 00 31 43 n // n depends on the printer // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=141 if (settings.cellSize) { const i = "QRCODE_CELLSIZE_" + settings.cellSize.toString(); if (!(this.config as any)[i]) { throw new Error("Invalid cellSize passed to printQR"); } this.append((this.config as any)[i]); } else { this.append(this.config.QRCODE_CELLSIZE_3); } // [Name] Select the error correction level // 1D 28 6B 03 00 31 45 n // n // [48 x30 -> 7%] // [49 x31-> 15%] // [50 x32 -> 25%] // [51 x33 -> 30%] // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=142 if (settings.correction) { const i = "QRCODE_CORRECTION_" + settings.correction.toUpperCase(); if (!(this.config as any)[i]) { throw new Error("Invalid correction passed to printQR"); } this.append((this.config as any)[i]); } else { this.append(this.config.QRCODE_CORRECTION_M); } // [Name] Store the data in the symbol storage area // 1D 28 6B pL pH 31 50 30 d1...dk // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=143 const s = str.length + 3; const lsb = s % 256; const msb = s / 256; this.append(Buffer.from([0x1d, 0x28, 0x6b, lsb, msb, 0x31, 0x50, 0x30])); this.append(Buffer.from(str)); // [Name] Print the symbol data in the symbol storage area // 1D 28 6B 03 00 31 51 m // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=144 this.append(this.config.QRCODE_PRINT); return this.buffer!; } // ------------------------------ PDF417 ------------------------------ pdf417( data: string, settings?: { rowHeight?: number; width?: number; correction?: number; truncated?: boolean; columns?: number; } ): Buffer { this.buffer = null; settings = settings || {}; // Set error correction ratio 1 - 40 if (settings.correction) { this.append(this.config.PDF417_CORRECTION); this.append(Buffer.from([settings.correction])); } else { this.append(this.config.PDF417_CORRECTION); this.append(Buffer.from([0x01])); } // Set row height 2 - 8 if (settings.rowHeight) { this.append(this.config.PDF417_ROW_HEIGHT); this.append(Buffer.from([settings.rowHeight])); } else { this.append(this.config.PDF417_ROW_HEIGHT); this.append(Buffer.from([0x03])); } // Set width of module 2 - 8 if (settings.width) { this.append(this.config.PDF417_WIDTH); this.append(Buffer.from([settings.width])); } else { this.append(this.config.PDF417_WIDTH); this.append(Buffer.from([0x03])); } // Manually set columns 1 - 30 if (settings.columns) { this.append(this.config.PDF417_COLUMNS); this.append(Buffer.from([settings.columns])); } else { // Default to auto this.append(this.config.PDF417_COLUMNS); this.append(Buffer.from([0x00])); } // Standard or truncated option if (settings.truncated) this.append(this.config.PDF417_OPTION_TRUNCATED); else this.append(this.config.PDF417_OPTION_STANDARD); // Set PDF417 bar code data const s = data.length + 3; const lsb = s % 256; const msb = s / 256; this.append(Buffer.from([0x1d, 0x28, 0x6b, lsb, msb, 0x30, 0x50, 0x30])); this.append(Buffer.from(data.toString())); // Print barcode this.append(Buffer.from(this.config.PDF417_PRINT)); return this.buffer!; } // ------------------------------ MAXI CODE ------------------------------ maxiCode( data: string, settings?: { mode?: number; } ): Buffer { this.buffer = null; settings = settings || {}; // Maxi Mode // 2 - Formatted data/structured Carrier Message with a numeric postal code. (US) // 3 - Formatted data/structured Carrier Message with a numeric postal code. (International) // 4 - Unformatted data/Standard Error Correction. // 5 - Unformatted data/Enhanced Error Correction. // 6 - Used for programming hardware devices. if (settings.mode) { if (settings.mode === 2) this.append(this.config.MAXI_MODE2); else if (settings.mode === 3) this.append(this.config.MAXI_MODE3); else if (settings.mode === 5) this.append(this.config.MAXI_MODE5); else if (settings.mode === 6) this.append(this.config.MAXI_MODE6); else this.append(this.config.MAXI_MODE4); } else { this.append(this.config.MAXI_MODE4); } // Setup size of MaxiCode data const s = data.length + 3; const lsb = s % 256; const msb = s / 256; // Send Data this.append(Buffer.from([0x1d, 0x28, 0x6b, lsb, msb, 0x32, 0x50, 0x30])); this.append(Buffer.from(data.toString())); // Print barcode this.append(this.config.MAXI_PRINT); return this.buffer!; } // ------------------------------ BARCODE ------------------------------ printBarcode( data: string, type: number = 74, settings?: { hriPos?: number; hriFont?: number; width?: number; height?: number; } ): Buffer { this.buffer = null; settings = settings || {}; //Set HRI characters Position, 0-3 (none, top, bottom, top/bottom) if (settings.hriPos) { this.append(Buffer.from([0x1d, 0x48])); // GS H this.append(Buffer.from([settings.hriPos])); } else { this.append(Buffer.from([0x1d, 0x48, 0x00])); } // Set HRI character font. 0-4, 48-52, 97, 98 (depending on printer, 0 and 1 available on all), default 0 if (settings.hriFont) { this.append(Buffer.from([0x1d, 0x66])); // GS f this.append(Buffer.from([settings.hriFont])); } else { this.append(Buffer.from([0x1d, 0x66, 0x00])); } // Set width 2-6, default 3 if (settings.width) { this.append(Buffer.from([0x1d, 0x77])); // GS W this.append(Buffer.from([settings.width])); } else { this.append(Buffer.from([0x1d, 0x77, 0x03])); } // Set height 1 - 255 default 162 if (settings.height) { this.append(Buffer.from([0x1d, 0x68])); // GS h this.append(Buffer.from([settings.height])); } else { this.append(Buffer.from([0x1d, 0x68, 0xa2])); } // Print Barcode this.append(Buffer.from([0x1d, 0x6b])); // GS k // Select type and bit length of data this.append(Buffer.from([type, data.length])); // Data this.append(Buffer.from(data)); return this.buffer!; } // ----------------------------------------------------- PRINT IMAGE ----------------------------------------------------- printImageBuffer(width: number, height: number, data: Buffer): Buffer { this.buffer = null; // Get pixel rgba in 2D array const pixels = []; for (let i = 0; i < height; i++) { const line = []; for (let j = 0; j < width; j++) { const idx = (width * i + j) << 2; line.push({ r: data[idx], g: data[idx + 1], b: data[idx + 2], a: data[idx + 3], }); } pixels.push(line); } const imageBuffer_array = []; for (let i = 0; i < height; i++) { for (let j = 0; j < Math.ceil(width / 8); j++) { var byte = 0x0; for (let k = 0; k < 8; k++) { var pixel = pixels[i][j * 8 + k]; // Image overflow if (pixel === undefined) { pixel = { a: 0, r: 0, g: 0, b: 0, }; } if (pixel.a > 126) { // checking transparency const grayscale = 0.2126 * pixel.r + 0.7152 * pixel.g + 0.0722 * pixel.b; if (grayscale < 128) { // checking color var mask = 1 << (7 - k); // setting bitwise mask byte |= mask; // setting the correct bit to 1 } } } imageBuffer_array.push(byte); // imageBuffer = Buffer.concat([imageBuffer, Buffer.from([byte])]); } } let imageBuffer = Buffer.from(imageBuffer_array); // Print raster bit image // GS v 0 // 1D 76 30 m xL xH yL yH d1...dk // xL = (this.width >> 3) & 0xff; // xH = 0x00; // yL = this.height & 0xff; // yH = (this.height >> 8) & 0xff; // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=94 // Check if width/8 is decimal if (width % 8 !== 0) { width += 8; } this.append(Buffer.from([0x1d, 0x76, 0x30, 48])); this.append(Buffer.from([(width >> 3) & 0xff])); this.append(Buffer.from([0x00])); this.append(Buffer.from([height & 0xff])); this.append(Buffer.from([(height >> 8) & 0xff])); // append data this.append(imageBuffer); return this.buffer!; } }