node-thermal-printer
Version:
Print on Epson, Star, Tranca, Daruma, Brother and Custom thermal printers with Node.js
338 lines (287 loc) • 10.5 kB
JavaScript
const PrinterType = require('./printer-type');
class Tanca extends PrinterType {
constructor () {
super();
this.config = require('./tanca-config');
}
// ------------------------------ Append ------------------------------
append (appendBuffer) {
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, width) {
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');
const x = Buffer.from(`${height}${width}`, 'hex');
this.append(Buffer.from([0x1D, 0x21]));
this.append(x);
return this.buffer;
}
// ------------------------------ QR ------------------------------
printQR (str, settings) {
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_'.concat(settings.cellSize.toString());
this.append(this.config[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_'.concat(settings.correction.toUpperCase());
this.append(this.config[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 = parseInt(s % 256);
const msb = parseInt(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, settings) {
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 = parseInt(s % 256);
const msb = parseInt(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, settings) {
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 = parseInt(s % 256);
const msb = parseInt(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, type, settings) {
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 -----------------------------------------------------
// https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=88
async printImage (image) {
const fs = require('fs');
const { PNG } = require('pngjs');
try {
const data = fs.readFileSync(image);
const png = PNG.sync.read(data);
const buff = this.printImageBuffer(png.width, png.height, png.data);
return buff;
} catch (error) {
throw error;
}
}
printImageBuffer (width, height, data) {
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 imageBufferArray = [];
for (let i = 0; i < height; i++) {
for (let j = 0; j < Math.ceil(width / 8); j++) {
let byte = 0x0;
for (let k = 0; k < 8; k++) {
let 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 = parseInt(0.2126 * pixel.r + 0.7152 * pixel.g + 0.0722 * pixel.b);
if (grayscale < 128) { // checking color
const mask = 1 << 7 - k; // setting bitwise mask
byte |= mask; // setting the correct bit to 1
}
}
}
imageBufferArray.push(byte);
// imageBuffer = Buffer.concat([imageBuffer, Buffer.from([byte])]);
}
}
const imageBuffer = Buffer.from(imageBufferArray);
// 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;
}
}
module.exports = Tanca;