@naphatjm/cdh-thermal-printer 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,50 @@ export interface PrintResponse {
|
|
|
11
11
|
message?: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Convert Thai text to ImageData (Client-side only)
|
|
16
|
+
*
|
|
17
|
+
* ⚠️ REQUIRED: Sarabun font must be loaded in your HTML:
|
|
18
|
+
* ```html
|
|
19
|
+
* <link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap" rel="stylesheet">
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @param text - Thai text to convert
|
|
23
|
+
* @param width - Canvas width in pixels (default: 384 = 58mm)
|
|
24
|
+
* @param fontSize - Font size in pixels (default: 22)
|
|
25
|
+
* @returns ImageData object ready for printing
|
|
26
|
+
* @throws Error if not in browser environment
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```javascript
|
|
30
|
+
* // Client-side
|
|
31
|
+
* const imageData = textToImageData("สวัสดี", 384, 22);
|
|
32
|
+
* await fetch('/api/print', {
|
|
33
|
+
* body: JSON.stringify({
|
|
34
|
+
* data: Array.from(imageData.data),
|
|
35
|
+
* width: imageData.width,
|
|
36
|
+
* height: imageData.height,
|
|
37
|
+
* })
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Server-side (API route)
|
|
41
|
+
* const printer = new ThermalPrinter();
|
|
42
|
+
* printer
|
|
43
|
+
* .init()
|
|
44
|
+
* .image({
|
|
45
|
+
* data: new Uint8ClampedArray(req.body.data),
|
|
46
|
+
* width: req.body.width,
|
|
47
|
+
* height: req.body.height,
|
|
48
|
+
* })
|
|
49
|
+
* .print("Printer Name");
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function textToImageData(
|
|
53
|
+
text: string,
|
|
54
|
+
width?: number,
|
|
55
|
+
fontSize?: number,
|
|
56
|
+
): ImageData;
|
|
57
|
+
|
|
14
58
|
/**
|
|
15
59
|
* ThermalPrinter Service
|
|
16
60
|
* Fluent API for controlling thermal printer with ESC/POS commands
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const s = {
|
|
2
2
|
ESC: 27,
|
|
3
3
|
GS: 29,
|
|
4
4
|
LF: 10,
|
|
@@ -18,44 +18,57 @@ const i = {
|
|
|
18
18
|
// Cash Drawer
|
|
19
19
|
DRAWER_KICK: [27, 112, 0, 12, 120],
|
|
20
20
|
// Beep (ESC B - default 100ms)
|
|
21
|
-
BEEP: (
|
|
21
|
+
BEEP: (a = 100) => [27, 66, a]
|
|
22
22
|
};
|
|
23
|
-
function
|
|
24
|
-
const e =
|
|
25
|
-
let
|
|
26
|
-
|
|
27
|
-
for (let
|
|
28
|
-
for (let c = 0; c <
|
|
29
|
-
let
|
|
30
|
-
for (let
|
|
31
|
-
const
|
|
32
|
-
r[
|
|
23
|
+
function d(a) {
|
|
24
|
+
const e = a.width, t = a.height, r = a.data, n = e / 8;
|
|
25
|
+
let o = [];
|
|
26
|
+
o.push(29, 118, 48, 0), o.push(n % 256, Math.floor(n / 256)), o.push(t % 256, Math.floor(t / 256));
|
|
27
|
+
for (let h = 0; h < t; h++)
|
|
28
|
+
for (let c = 0; c < n; c++) {
|
|
29
|
+
let f = 0;
|
|
30
|
+
for (let i = 0; i < 8; i++) {
|
|
31
|
+
const l = (h * e + c * 8 + i) * 4;
|
|
32
|
+
r[l] + r[l + 1] + r[l + 2] < 380 && (f |= 1 << 7 - i);
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
o.push(f);
|
|
35
35
|
}
|
|
36
|
-
return
|
|
36
|
+
return o;
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
function p(a, e = 384, t = 22) {
|
|
39
|
+
if (typeof document > "u")
|
|
40
|
+
throw new Error(
|
|
41
|
+
"textToImageData() requires browser environment with Canvas API"
|
|
42
|
+
);
|
|
43
|
+
const r = document.createElement("canvas"), n = r.getContext("2d"), o = "'Sarabun', sans-serif", h = t + 12, c = a.split(`
|
|
44
|
+
`), f = c.length * h + 20;
|
|
45
|
+
r.width = e, r.height = f, n.fillStyle = "white", n.fillRect(0, 0, r.width, r.height), n.fillStyle = "black", n.font = `${t}px ${o}`, n.textBaseline = "top";
|
|
46
|
+
let i = 10;
|
|
47
|
+
for (let l of c)
|
|
48
|
+
n.fillText(l, 10, i), i += h;
|
|
49
|
+
return n.getImageData(0, 0, e, f);
|
|
50
|
+
}
|
|
51
|
+
class x {
|
|
39
52
|
constructor(e = "http://localhost:9123", t = 384) {
|
|
40
53
|
this.driverApi = e, this.printerWidth = t, this.buffer = [];
|
|
41
54
|
}
|
|
42
55
|
// --- Basic Commands ---
|
|
43
56
|
init() {
|
|
44
|
-
return this.buffer.push(...
|
|
57
|
+
return this.buffer.push(...s.INIT), this;
|
|
45
58
|
}
|
|
46
59
|
align(e = 1) {
|
|
47
|
-
const t = [...
|
|
60
|
+
const t = [...s.ALIGN_LEFT];
|
|
48
61
|
return t[2] = e, this.buffer.push(...t), this;
|
|
49
62
|
}
|
|
50
63
|
bold(e = !0) {
|
|
51
|
-
return this.buffer.push(...e ?
|
|
64
|
+
return this.buffer.push(...e ? s.BOLD_ON : s.BOLD_OFF), this;
|
|
52
65
|
}
|
|
53
66
|
feed(e = 1) {
|
|
54
|
-
for (let t = 0; t < e; t++) this.buffer.push(
|
|
67
|
+
for (let t = 0; t < e; t++) this.buffer.push(s.LF);
|
|
55
68
|
return this;
|
|
56
69
|
}
|
|
57
70
|
cut(e = !1) {
|
|
58
|
-
return this.buffer.push(...e ?
|
|
71
|
+
return this.buffer.push(...e ? s.CUT_PARTIAL : s.CUT_FULL), this;
|
|
59
72
|
}
|
|
60
73
|
line(e = "") {
|
|
61
74
|
const r = new TextEncoder().encode(e + `
|
|
@@ -64,7 +77,7 @@ class l {
|
|
|
64
77
|
}
|
|
65
78
|
newline(e = 1) {
|
|
66
79
|
for (let t = 0; t < e; t++)
|
|
67
|
-
this.buffer.push(
|
|
80
|
+
this.buffer.push(s.LF);
|
|
68
81
|
return this;
|
|
69
82
|
}
|
|
70
83
|
divider(e = "-", t = 32) {
|
|
@@ -72,18 +85,18 @@ class l {
|
|
|
72
85
|
}
|
|
73
86
|
beep(e = 1, t = 100) {
|
|
74
87
|
for (let r = 0; r < e; r++)
|
|
75
|
-
this.buffer.push(...
|
|
88
|
+
this.buffer.push(...s.BEEP(t));
|
|
76
89
|
return this;
|
|
77
90
|
}
|
|
78
91
|
drawerKick() {
|
|
79
|
-
return this.buffer.push(...
|
|
92
|
+
return this.buffer.push(...s.DRAWER_KICK), this;
|
|
80
93
|
}
|
|
81
94
|
raw(e) {
|
|
82
95
|
return this.buffer.push(...e), this;
|
|
83
96
|
}
|
|
84
97
|
// --- Image & Thai Text Logic ---
|
|
85
98
|
image(e) {
|
|
86
|
-
const t =
|
|
99
|
+
const t = d(e);
|
|
87
100
|
return this.buffer.push(...t), this;
|
|
88
101
|
}
|
|
89
102
|
/**
|
|
@@ -100,14 +113,14 @@ class l {
|
|
|
100
113
|
printThaiText(e, t = 22) {
|
|
101
114
|
if (typeof document > "u")
|
|
102
115
|
return console.error("Browser environment required for printThaiText"), this;
|
|
103
|
-
const r = document.createElement("canvas"),
|
|
104
|
-
`),
|
|
105
|
-
r.width = this.printerWidth, r.height =
|
|
106
|
-
let
|
|
107
|
-
for (let
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
return this.image(
|
|
116
|
+
const r = document.createElement("canvas"), n = r.getContext("2d"), o = "'Sarabun', sans-serif", h = t + 12, c = e.split(`
|
|
117
|
+
`), f = c.length * h + 20;
|
|
118
|
+
r.width = this.printerWidth, r.height = f, n.fillStyle = "white", n.fillRect(0, 0, r.width, r.height), n.fillStyle = "black", n.font = `${t}px ${o}`, n.textBaseline = "top";
|
|
119
|
+
let i = 10;
|
|
120
|
+
for (let u of c)
|
|
121
|
+
n.fillText(u, 10, i), i += h;
|
|
122
|
+
const l = n.getImageData(0, 0, this.printerWidth, f);
|
|
123
|
+
return this.image(l);
|
|
111
124
|
}
|
|
112
125
|
// --- Execution ---
|
|
113
126
|
clear() {
|
|
@@ -118,7 +131,7 @@ class l {
|
|
|
118
131
|
}
|
|
119
132
|
async print(e) {
|
|
120
133
|
if (!e) {
|
|
121
|
-
const t = await
|
|
134
|
+
const t = await x.getPrinters(this.driverApi);
|
|
122
135
|
if (t.length > 0) e = t[0];
|
|
123
136
|
else throw new Error("No printer found.");
|
|
124
137
|
}
|
|
@@ -147,6 +160,7 @@ class l {
|
|
|
147
160
|
}
|
|
148
161
|
}
|
|
149
162
|
export {
|
|
150
|
-
|
|
163
|
+
x as ThermalPrinter,
|
|
164
|
+
p as textToImageData
|
|
151
165
|
};
|
|
152
166
|
//# sourceMappingURL=thermal-printer.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thermal-printer.es.js","sources":["../src/constants.js","../src/utils.js","../src/index.js"],"sourcesContent":["// src/constants.js\r\nexport const CMD = {\r\n ESC: 0x1b,\r\n GS: 0x1d,\r\n LF: 0x0a,\r\n\r\n // Commands\r\n INIT: [0x1b, 0x40], // Initialize printer\r\n CUT_FULL: [0x1d, 0x56, 0x42, 0x00], // Full cut\r\n CUT_PARTIAL: [0x1d, 0x56, 0x41, 0x00], // Partial cut\r\n\r\n // Formatting\r\n BOLD_ON: [0x1b, 0x45, 0x01],\r\n BOLD_OFF: [0x1b, 0x45, 0x00],\r\n\r\n ALIGN_LEFT: [0x1b, 0x61, 0x00],\r\n ALIGN_CENTER: [0x1b, 0x61, 0x01],\r\n ALIGN_RIGHT: [0x1b, 0x61, 0x02],\r\n\r\n // Cash Drawer\r\n DRAWER_KICK: [0x1b, 0x70, 0x00, 0x0c, 0x78],\r\n\r\n // Beep (ESC B - default 100ms)\r\n BEEP: (duration = 100) => [0x1b, 0x42, duration],\r\n};\r\n","// src/utils.js\r\n\r\n/**\r\n * แปลงข้อมูลภาพ (ImageData) เป็นคำสั่ง ESC/POS GS v 0\r\n * @param {ImageData} imageData\r\n * @returns {number[]} Array ของ Byte คำสั่ง\r\n */\r\nexport function convertCanvasToEscPos(imageData) {\r\n const width = imageData.width;\r\n const height = imageData.height;\r\n const pixels = imageData.data;\r\n\r\n // 1 Byte = 8 pixels แนวนอน\r\n const xBytes = width / 8;\r\n\r\n let command = [];\r\n\r\n // Header: GS v 0 (Raster Bit Image)\r\n command.push(0x1d, 0x76, 0x30, 0x00);\r\n\r\n // บอกขนาดภาพ (Little Endian)\r\n command.push(xBytes % 256, Math.floor(xBytes / 256)); // xL, xH\r\n command.push(height % 256, Math.floor(height / 256)); // yL, yH\r\n\r\n // Loop ทุก Pixel แปลงเป็น Bit\r\n for (let y = 0; y < height; y++) {\r\n for (let x = 0; x < xBytes; x++) {\r\n let byte = 0;\r\n for (let bit = 0; bit < 8; bit++) {\r\n // คำนวณตำแหน่ง Pixel ใน Array (RGBA = 4 ช่องต่อ 1 pixel)\r\n const pxIndex = (y * width + x * 8 + bit) * 4;\r\n\r\n // เช็คความสว่าง (R+G+B)\r\n // ถ้าค่าต่ำกว่า 380 (ค่อนข้างมืด) ให้ถือเป็นสีดำ (Bit=1)\r\n const brightness =\r\n pixels[pxIndex] + pixels[pxIndex + 1] + pixels[pxIndex + 2];\r\n if (brightness < 380) {\r\n byte |= 1 << (7 - bit);\r\n }\r\n }\r\n command.push(byte);\r\n }\r\n }\r\n\r\n return command;\r\n}\r\n","// src/index.js\r\nimport { CMD } from \"./constants\";\r\nimport { convertCanvasToEscPos } from \"./utils\";\r\n\r\n/**\r\n * Thermal Printer Library for ESC/POS printers\r\n *\r\n * IMPORTANT: When using printThaiText(), you must load the Sarabun font in your HTML:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the printer will use the default system font instead of Sarabun.\r\n */\r\nexport class ThermalPrinter {\r\n constructor(driverApiUrl = \"http://localhost:9123\", width = 384) {\r\n this.driverApi = driverApiUrl;\r\n this.printerWidth = width; // 384 dots = 58mm, 576 dots = 80mm\r\n this.buffer = [];\r\n }\r\n\r\n // --- Basic Commands ---\r\n\r\n init() {\r\n this.buffer.push(...CMD.INIT);\r\n return this;\r\n }\r\n\r\n align(alignment = 1) {\r\n // 0=Left, 1=Center, 2=Right\r\n const cmd = [...CMD.ALIGN_LEFT];\r\n cmd[2] = alignment;\r\n this.buffer.push(...cmd);\r\n return this;\r\n }\r\n\r\n bold(enable = true) {\r\n this.buffer.push(...(enable ? CMD.BOLD_ON : CMD.BOLD_OFF));\r\n return this;\r\n }\r\n\r\n feed(lines = 1) {\r\n for (let i = 0; i < lines; i++) this.buffer.push(CMD.LF);\r\n return this;\r\n }\r\n\r\n cut(partial = false) {\r\n this.buffer.push(...(partial ? CMD.CUT_PARTIAL : CMD.CUT_FULL));\r\n return this;\r\n }\r\n\r\n line(text = \"\") {\r\n const encoder = new TextEncoder();\r\n const bytes = encoder.encode(text + \"\\n\");\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n newline(count = 1) {\r\n for (let i = 0; i < count; i++) {\r\n this.buffer.push(CMD.LF);\r\n }\r\n return this;\r\n }\r\n\r\n divider(char = \"-\", width = 32) {\r\n this.line(char.repeat(width));\r\n return this;\r\n }\r\n\r\n beep(times = 1, duration = 100) {\r\n for (let i = 0; i < times; i++) {\r\n this.buffer.push(...CMD.BEEP(duration));\r\n }\r\n return this;\r\n }\r\n\r\n drawerKick() {\r\n this.buffer.push(...CMD.DRAWER_KICK);\r\n return this;\r\n }\r\n\r\n raw(bytes) {\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n // --- Image & Thai Text Logic ---\r\n\r\n image(imageData) {\r\n const bytes = convertCanvasToEscPos(imageData);\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n /**\r\n * พิมพ์ข้อความภาษาไทย (Render เป็นรูปภาพอัตโนมัติ)\r\n *\r\n * ⚠️ REQUIRED: Sarabun font must be loaded in your HTML file:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the system will use the default font instead.\r\n *\r\n * @param {string} text - Thai text to print\r\n * @param {number} fontSize - Font size in pixels (default: 22)\r\n */\r\n printThaiText(text, fontSize = 22) {\r\n if (typeof document === \"undefined\") {\r\n console.error(\"Browser environment required for printThaiText\");\r\n return this;\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\");\r\n const ctx = canvas.getContext(\"2d\");\r\n\r\n // ตั้งค่า Font\r\n const fontFamily = \"'Sarabun', sans-serif\";\r\n const lineHeight = fontSize + 12;\r\n const lines = text.split(\"\\n\");\r\n\r\n // คำนวณความสูง\r\n const height = lines.length * lineHeight + 20;\r\n\r\n canvas.width = this.printerWidth;\r\n canvas.height = height;\r\n\r\n // วาดพื้นหลังขาว\r\n ctx.fillStyle = \"white\";\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n // วาดข้อความ\r\n ctx.fillStyle = \"black\";\r\n ctx.font = `${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = \"top\";\r\n\r\n let y = 10;\r\n for (let line of lines) {\r\n ctx.fillText(line, 10, y);\r\n y += lineHeight;\r\n }\r\n\r\n const imageData = ctx.getImageData(0, 0, this.printerWidth, height);\r\n return this.image(imageData);\r\n }\r\n\r\n // --- Execution ---\r\n\r\n clear() {\r\n this.buffer = [];\r\n return this;\r\n }\r\n\r\n getBuffer() {\r\n return new Uint8Array(this.buffer);\r\n }\r\n\r\n async print(printerName) {\r\n // ถ้าไม่ส่งชื่อมา ให้ลองดึงตัวแรก\r\n if (!printerName) {\r\n const printers = await ThermalPrinter.getPrinters(this.driverApi);\r\n if (printers.length > 0) printerName = printers[0];\r\n else throw new Error(\"No printer found.\");\r\n }\r\n\r\n try {\r\n const bufferData = this.getBuffer();\r\n const encodedName = encodeURIComponent(printerName);\r\n\r\n const res = await fetch(\r\n `${this.driverApi}/print?printer=${encodedName}`,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/octet-stream\" },\r\n body: bufferData,\r\n },\r\n );\r\n\r\n if (!res.ok) throw new Error(\"Driver Error\");\r\n\r\n this.clear();\r\n return { success: true };\r\n } catch (e) {\r\n console.error(\"Print Failed:\", e);\r\n throw e;\r\n }\r\n }\r\n\r\n // --- Static Methods ---\r\n\r\n static async getPrinters(apiUrl = \"http://localhost:9123\") {\r\n try {\r\n const res = await fetch(`${apiUrl}/printers`);\r\n return await res.json();\r\n } catch (e) {\r\n console.error(\"Connection Error:\", e);\r\n return [];\r\n }\r\n }\r\n}\r\n"],"names":["CMD","duration","convertCanvasToEscPos","imageData","width","height","pixels","xBytes","command","y","x","byte","bit","pxIndex","ThermalPrinter","driverApiUrl","alignment","cmd","enable","lines","i","partial","text","bytes","count","char","times","fontSize","canvas","ctx","fontFamily","lineHeight","line","printerName","printers","bufferData","encodedName","e","apiUrl"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"thermal-printer.es.js","sources":["../src/constants.js","../src/utils.js","../src/index.js"],"sourcesContent":["// src/constants.js\r\nexport const CMD = {\r\n ESC: 0x1b,\r\n GS: 0x1d,\r\n LF: 0x0a,\r\n\r\n // Commands\r\n INIT: [0x1b, 0x40], // Initialize printer\r\n CUT_FULL: [0x1d, 0x56, 0x42, 0x00], // Full cut\r\n CUT_PARTIAL: [0x1d, 0x56, 0x41, 0x00], // Partial cut\r\n\r\n // Formatting\r\n BOLD_ON: [0x1b, 0x45, 0x01],\r\n BOLD_OFF: [0x1b, 0x45, 0x00],\r\n\r\n ALIGN_LEFT: [0x1b, 0x61, 0x00],\r\n ALIGN_CENTER: [0x1b, 0x61, 0x01],\r\n ALIGN_RIGHT: [0x1b, 0x61, 0x02],\r\n\r\n // Cash Drawer\r\n DRAWER_KICK: [0x1b, 0x70, 0x00, 0x0c, 0x78],\r\n\r\n // Beep (ESC B - default 100ms)\r\n BEEP: (duration = 100) => [0x1b, 0x42, duration],\r\n};\r\n","// src/utils.js\r\n\r\n/**\r\n * แปลงข้อมูลภาพ (ImageData) เป็นคำสั่ง ESC/POS GS v 0\r\n * @param {ImageData} imageData\r\n * @returns {number[]} Array ของ Byte คำสั่ง\r\n */\r\nexport function convertCanvasToEscPos(imageData) {\r\n const width = imageData.width;\r\n const height = imageData.height;\r\n const pixels = imageData.data;\r\n\r\n // 1 Byte = 8 pixels แนวนอน\r\n const xBytes = width / 8;\r\n\r\n let command = [];\r\n\r\n // Header: GS v 0 (Raster Bit Image)\r\n command.push(0x1d, 0x76, 0x30, 0x00);\r\n\r\n // บอกขนาดภาพ (Little Endian)\r\n command.push(xBytes % 256, Math.floor(xBytes / 256)); // xL, xH\r\n command.push(height % 256, Math.floor(height / 256)); // yL, yH\r\n\r\n // Loop ทุก Pixel แปลงเป็น Bit\r\n for (let y = 0; y < height; y++) {\r\n for (let x = 0; x < xBytes; x++) {\r\n let byte = 0;\r\n for (let bit = 0; bit < 8; bit++) {\r\n // คำนวณตำแหน่ง Pixel ใน Array (RGBA = 4 ช่องต่อ 1 pixel)\r\n const pxIndex = (y * width + x * 8 + bit) * 4;\r\n\r\n // เช็คความสว่าง (R+G+B)\r\n // ถ้าค่าต่ำกว่า 380 (ค่อนข้างมืด) ให้ถือเป็นสีดำ (Bit=1)\r\n const brightness =\r\n pixels[pxIndex] + pixels[pxIndex + 1] + pixels[pxIndex + 2];\r\n if (brightness < 380) {\r\n byte |= 1 << (7 - bit);\r\n }\r\n }\r\n command.push(byte);\r\n }\r\n }\r\n\r\n return command;\r\n}\r\n/**\r\n * แปลงข้อความเป็น ImageData (Client-side only)\r\n * ต้องใช้ใน Browser environment เท่านั้น\r\n *\r\n * ⚠️ REQUIRED: Sarabun font must be loaded in your HTML:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * @param {string} text - Thai text to convert\r\n * @param {number} width - Canvas width in pixels (default: 384)\r\n * @param {number} fontSize - Font size in pixels (default: 22)\r\n * @returns {ImageData} Canvas ImageData object\r\n * @throws {Error} If not in browser environment\r\n *\r\n * @example\r\n * // Client-side (React/Next.js)\r\n * const imageData = textToImageData(\"สวัสดี\", 384, 22);\r\n * await fetch('/api/print', {\r\n * body: JSON.stringify({\r\n * data: Array.from(imageData.data),\r\n * width: imageData.width,\r\n * height: imageData.height,\r\n * })\r\n * });\r\n */\r\nexport function textToImageData(text, width = 384, fontSize = 22) {\r\n // ตรวจสอบว่าเป็น Browser environment\r\n if (typeof document === \"undefined\") {\r\n throw new Error(\r\n \"textToImageData() requires browser environment with Canvas API\",\r\n );\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\");\r\n const ctx = canvas.getContext(\"2d\");\r\n\r\n // ตั้งค่า Font\r\n const fontFamily = \"'Sarabun', sans-serif\";\r\n const lineHeight = fontSize + 12;\r\n const lines = text.split(\"\\n\");\r\n\r\n // คำนวณความสูง\r\n const height = lines.length * lineHeight + 20;\r\n\r\n canvas.width = width;\r\n canvas.height = height;\r\n\r\n // วาดพื้นหลังขาว\r\n ctx.fillStyle = \"white\";\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n // วาดข้อความ\r\n ctx.fillStyle = \"black\";\r\n ctx.font = `${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = \"top\";\r\n\r\n let y = 10;\r\n for (let line of lines) {\r\n ctx.fillText(line, 10, y);\r\n y += lineHeight;\r\n }\r\n\r\n // ดึง ImageData\r\n return ctx.getImageData(0, 0, width, height);\r\n}\r\n","// src/index.js\r\nimport { CMD } from \"./constants\";\r\nimport { convertCanvasToEscPos, textToImageData } from \"./utils\";\r\n\r\n/**\r\n * Thermal Printer Library for ESC/POS printers\r\n *\r\n * IMPORTANT: When using printThaiText() or textToImageData(), you must load the Sarabun font in your HTML:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the printer will use the default system font instead of Sarabun.\r\n */\r\nexport { textToImageData } from \"./utils\";\r\nexport class ThermalPrinter {\r\n constructor(driverApiUrl = \"http://localhost:9123\", width = 384) {\r\n this.driverApi = driverApiUrl;\r\n this.printerWidth = width; // 384 dots = 58mm, 576 dots = 80mm\r\n this.buffer = [];\r\n }\r\n\r\n // --- Basic Commands ---\r\n\r\n init() {\r\n this.buffer.push(...CMD.INIT);\r\n return this;\r\n }\r\n\r\n align(alignment = 1) {\r\n // 0=Left, 1=Center, 2=Right\r\n const cmd = [...CMD.ALIGN_LEFT];\r\n cmd[2] = alignment;\r\n this.buffer.push(...cmd);\r\n return this;\r\n }\r\n\r\n bold(enable = true) {\r\n this.buffer.push(...(enable ? CMD.BOLD_ON : CMD.BOLD_OFF));\r\n return this;\r\n }\r\n\r\n feed(lines = 1) {\r\n for (let i = 0; i < lines; i++) this.buffer.push(CMD.LF);\r\n return this;\r\n }\r\n\r\n cut(partial = false) {\r\n this.buffer.push(...(partial ? CMD.CUT_PARTIAL : CMD.CUT_FULL));\r\n return this;\r\n }\r\n\r\n line(text = \"\") {\r\n const encoder = new TextEncoder();\r\n const bytes = encoder.encode(text + \"\\n\");\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n newline(count = 1) {\r\n for (let i = 0; i < count; i++) {\r\n this.buffer.push(CMD.LF);\r\n }\r\n return this;\r\n }\r\n\r\n divider(char = \"-\", width = 32) {\r\n this.line(char.repeat(width));\r\n return this;\r\n }\r\n\r\n beep(times = 1, duration = 100) {\r\n for (let i = 0; i < times; i++) {\r\n this.buffer.push(...CMD.BEEP(duration));\r\n }\r\n return this;\r\n }\r\n\r\n drawerKick() {\r\n this.buffer.push(...CMD.DRAWER_KICK);\r\n return this;\r\n }\r\n\r\n raw(bytes) {\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n // --- Image & Thai Text Logic ---\r\n\r\n image(imageData) {\r\n const bytes = convertCanvasToEscPos(imageData);\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n /**\r\n * พิมพ์ข้อความภาษาไทย (Render เป็นรูปภาพอัตโนมัติ)\r\n *\r\n * ⚠️ REQUIRED: Sarabun font must be loaded in your HTML file:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the system will use the default font instead.\r\n *\r\n * @param {string} text - Thai text to print\r\n * @param {number} fontSize - Font size in pixels (default: 22)\r\n */\r\n printThaiText(text, fontSize = 22) {\r\n if (typeof document === \"undefined\") {\r\n console.error(\"Browser environment required for printThaiText\");\r\n return this;\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\");\r\n const ctx = canvas.getContext(\"2d\");\r\n\r\n // ตั้งค่า Font\r\n const fontFamily = \"'Sarabun', sans-serif\";\r\n const lineHeight = fontSize + 12;\r\n const lines = text.split(\"\\n\");\r\n\r\n // คำนวณความสูง\r\n const height = lines.length * lineHeight + 20;\r\n\r\n canvas.width = this.printerWidth;\r\n canvas.height = height;\r\n\r\n // วาดพื้นหลังขาว\r\n ctx.fillStyle = \"white\";\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n // วาดข้อความ\r\n ctx.fillStyle = \"black\";\r\n ctx.font = `${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = \"top\";\r\n\r\n let y = 10;\r\n for (let line of lines) {\r\n ctx.fillText(line, 10, y);\r\n y += lineHeight;\r\n }\r\n\r\n const imageData = ctx.getImageData(0, 0, this.printerWidth, height);\r\n return this.image(imageData);\r\n }\r\n\r\n // --- Execution ---\r\n\r\n clear() {\r\n this.buffer = [];\r\n return this;\r\n }\r\n\r\n getBuffer() {\r\n return new Uint8Array(this.buffer);\r\n }\r\n\r\n async print(printerName) {\r\n // ถ้าไม่ส่งชื่อมา ให้ลองดึงตัวแรก\r\n if (!printerName) {\r\n const printers = await ThermalPrinter.getPrinters(this.driverApi);\r\n if (printers.length > 0) printerName = printers[0];\r\n else throw new Error(\"No printer found.\");\r\n }\r\n\r\n try {\r\n const bufferData = this.getBuffer();\r\n const encodedName = encodeURIComponent(printerName);\r\n\r\n const res = await fetch(\r\n `${this.driverApi}/print?printer=${encodedName}`,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/octet-stream\" },\r\n body: bufferData,\r\n },\r\n );\r\n\r\n if (!res.ok) throw new Error(\"Driver Error\");\r\n\r\n this.clear();\r\n return { success: true };\r\n } catch (e) {\r\n console.error(\"Print Failed:\", e);\r\n throw e;\r\n }\r\n }\r\n\r\n // --- Static Methods ---\r\n\r\n static async getPrinters(apiUrl = \"http://localhost:9123\") {\r\n try {\r\n const res = await fetch(`${apiUrl}/printers`);\r\n return await res.json();\r\n } catch (e) {\r\n console.error(\"Connection Error:\", e);\r\n return [];\r\n }\r\n }\r\n}\r\n"],"names":["CMD","duration","convertCanvasToEscPos","imageData","width","height","pixels","xBytes","command","y","x","byte","bit","pxIndex","textToImageData","text","fontSize","canvas","ctx","fontFamily","lineHeight","lines","line","ThermalPrinter","driverApiUrl","alignment","cmd","enable","i","partial","bytes","count","char","times","printerName","printers","bufferData","encodedName","e","apiUrl"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
`);
|
|
3
|
-
`)
|
|
1
|
+
(function(a,i){typeof exports=="object"&&typeof module<"u"?i(exports):typeof define=="function"&&define.amd?define(["exports"],i):(a=typeof globalThis<"u"?globalThis:a||self,i(a.ThermalPrinter={}))})(this,(function(a){"use strict";const i={ESC:27,GS:29,LF:10,INIT:[27,64],CUT_FULL:[29,86,66,0],CUT_PARTIAL:[29,86,65,0],BOLD_ON:[27,69,1],BOLD_OFF:[27,69,0],ALIGN_LEFT:[27,97,0],ALIGN_CENTER:[27,97,1],ALIGN_RIGHT:[27,97,2],DRAWER_KICK:[27,112,0,12,120],BEEP:(l=100)=>[27,66,l]};function p(l){const e=l.width,t=l.height,r=l.data,n=e/8;let o=[];o.push(29,118,48,0),o.push(n%256,Math.floor(n/256)),o.push(t%256,Math.floor(t/256));for(let h=0;h<t;h++)for(let c=0;c<n;c++){let f=0;for(let s=0;s<8;s++){const u=(h*e+c*8+s)*4;r[u]+r[u+1]+r[u+2]<380&&(f|=1<<7-s)}o.push(f)}return o}function b(l,e=384,t=22){if(typeof document>"u")throw new Error("textToImageData() requires browser environment with Canvas API");const r=document.createElement("canvas"),n=r.getContext("2d"),o="'Sarabun', sans-serif",h=t+12,c=l.split(`
|
|
2
|
+
`),f=c.length*h+20;r.width=e,r.height=f,n.fillStyle="white",n.fillRect(0,0,r.width,r.height),n.fillStyle="black",n.font=`${t}px ${o}`,n.textBaseline="top";let s=10;for(let u of c)n.fillText(u,10,s),s+=h;return n.getImageData(0,0,e,f)}class x{constructor(e="http://localhost:9123",t=384){this.driverApi=e,this.printerWidth=t,this.buffer=[]}init(){return this.buffer.push(...i.INIT),this}align(e=1){const t=[...i.ALIGN_LEFT];return t[2]=e,this.buffer.push(...t),this}bold(e=!0){return this.buffer.push(...e?i.BOLD_ON:i.BOLD_OFF),this}feed(e=1){for(let t=0;t<e;t++)this.buffer.push(i.LF);return this}cut(e=!1){return this.buffer.push(...e?i.CUT_PARTIAL:i.CUT_FULL),this}line(e=""){const r=new TextEncoder().encode(e+`
|
|
3
|
+
`);return this.buffer.push(...r),this}newline(e=1){for(let t=0;t<e;t++)this.buffer.push(i.LF);return this}divider(e="-",t=32){return this.line(e.repeat(t)),this}beep(e=1,t=100){for(let r=0;r<e;r++)this.buffer.push(...i.BEEP(t));return this}drawerKick(){return this.buffer.push(...i.DRAWER_KICK),this}raw(e){return this.buffer.push(...e),this}image(e){const t=p(e);return this.buffer.push(...t),this}printThaiText(e,t=22){if(typeof document>"u")return console.error("Browser environment required for printThaiText"),this;const r=document.createElement("canvas"),n=r.getContext("2d"),o="'Sarabun', sans-serif",h=t+12,c=e.split(`
|
|
4
|
+
`),f=c.length*h+20;r.width=this.printerWidth,r.height=f,n.fillStyle="white",n.fillRect(0,0,r.width,r.height),n.fillStyle="black",n.font=`${t}px ${o}`,n.textBaseline="top";let s=10;for(let d of c)n.fillText(d,10,s),s+=h;const u=n.getImageData(0,0,this.printerWidth,f);return this.image(u)}clear(){return this.buffer=[],this}getBuffer(){return new Uint8Array(this.buffer)}async print(e){if(!e){const t=await x.getPrinters(this.driverApi);if(t.length>0)e=t[0];else throw new Error("No printer found.")}try{const t=this.getBuffer(),r=encodeURIComponent(e);if(!(await fetch(`${this.driverApi}/print?printer=${r}`,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:t})).ok)throw new Error("Driver Error");return this.clear(),{success:!0}}catch(t){throw console.error("Print Failed:",t),t}}static async getPrinters(e="http://localhost:9123"){try{return await(await fetch(`${e}/printers`)).json()}catch(t){return console.error("Connection Error:",t),[]}}}a.ThermalPrinter=x,a.textToImageData=b,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
|
|
4
5
|
//# sourceMappingURL=thermal-printer.umd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thermal-printer.umd.js","sources":["../src/constants.js","../src/utils.js","../src/index.js"],"sourcesContent":["// src/constants.js\r\nexport const CMD = {\r\n ESC: 0x1b,\r\n GS: 0x1d,\r\n LF: 0x0a,\r\n\r\n // Commands\r\n INIT: [0x1b, 0x40], // Initialize printer\r\n CUT_FULL: [0x1d, 0x56, 0x42, 0x00], // Full cut\r\n CUT_PARTIAL: [0x1d, 0x56, 0x41, 0x00], // Partial cut\r\n\r\n // Formatting\r\n BOLD_ON: [0x1b, 0x45, 0x01],\r\n BOLD_OFF: [0x1b, 0x45, 0x00],\r\n\r\n ALIGN_LEFT: [0x1b, 0x61, 0x00],\r\n ALIGN_CENTER: [0x1b, 0x61, 0x01],\r\n ALIGN_RIGHT: [0x1b, 0x61, 0x02],\r\n\r\n // Cash Drawer\r\n DRAWER_KICK: [0x1b, 0x70, 0x00, 0x0c, 0x78],\r\n\r\n // Beep (ESC B - default 100ms)\r\n BEEP: (duration = 100) => [0x1b, 0x42, duration],\r\n};\r\n","// src/utils.js\r\n\r\n/**\r\n * แปลงข้อมูลภาพ (ImageData) เป็นคำสั่ง ESC/POS GS v 0\r\n * @param {ImageData} imageData\r\n * @returns {number[]} Array ของ Byte คำสั่ง\r\n */\r\nexport function convertCanvasToEscPos(imageData) {\r\n const width = imageData.width;\r\n const height = imageData.height;\r\n const pixels = imageData.data;\r\n\r\n // 1 Byte = 8 pixels แนวนอน\r\n const xBytes = width / 8;\r\n\r\n let command = [];\r\n\r\n // Header: GS v 0 (Raster Bit Image)\r\n command.push(0x1d, 0x76, 0x30, 0x00);\r\n\r\n // บอกขนาดภาพ (Little Endian)\r\n command.push(xBytes % 256, Math.floor(xBytes / 256)); // xL, xH\r\n command.push(height % 256, Math.floor(height / 256)); // yL, yH\r\n\r\n // Loop ทุก Pixel แปลงเป็น Bit\r\n for (let y = 0; y < height; y++) {\r\n for (let x = 0; x < xBytes; x++) {\r\n let byte = 0;\r\n for (let bit = 0; bit < 8; bit++) {\r\n // คำนวณตำแหน่ง Pixel ใน Array (RGBA = 4 ช่องต่อ 1 pixel)\r\n const pxIndex = (y * width + x * 8 + bit) * 4;\r\n\r\n // เช็คความสว่าง (R+G+B)\r\n // ถ้าค่าต่ำกว่า 380 (ค่อนข้างมืด) ให้ถือเป็นสีดำ (Bit=1)\r\n const brightness =\r\n pixels[pxIndex] + pixels[pxIndex + 1] + pixels[pxIndex + 2];\r\n if (brightness < 380) {\r\n byte |= 1 << (7 - bit);\r\n }\r\n }\r\n command.push(byte);\r\n }\r\n }\r\n\r\n return command;\r\n}\r\n","// src/index.js\r\nimport { CMD } from \"./constants\";\r\nimport { convertCanvasToEscPos } from \"./utils\";\r\n\r\n/**\r\n * Thermal Printer Library for ESC/POS printers\r\n *\r\n * IMPORTANT: When using printThaiText(), you must load the Sarabun font in your HTML:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the printer will use the default system font instead of Sarabun.\r\n */\r\nexport class ThermalPrinter {\r\n constructor(driverApiUrl = \"http://localhost:9123\", width = 384) {\r\n this.driverApi = driverApiUrl;\r\n this.printerWidth = width; // 384 dots = 58mm, 576 dots = 80mm\r\n this.buffer = [];\r\n }\r\n\r\n // --- Basic Commands ---\r\n\r\n init() {\r\n this.buffer.push(...CMD.INIT);\r\n return this;\r\n }\r\n\r\n align(alignment = 1) {\r\n // 0=Left, 1=Center, 2=Right\r\n const cmd = [...CMD.ALIGN_LEFT];\r\n cmd[2] = alignment;\r\n this.buffer.push(...cmd);\r\n return this;\r\n }\r\n\r\n bold(enable = true) {\r\n this.buffer.push(...(enable ? CMD.BOLD_ON : CMD.BOLD_OFF));\r\n return this;\r\n }\r\n\r\n feed(lines = 1) {\r\n for (let i = 0; i < lines; i++) this.buffer.push(CMD.LF);\r\n return this;\r\n }\r\n\r\n cut(partial = false) {\r\n this.buffer.push(...(partial ? CMD.CUT_PARTIAL : CMD.CUT_FULL));\r\n return this;\r\n }\r\n\r\n line(text = \"\") {\r\n const encoder = new TextEncoder();\r\n const bytes = encoder.encode(text + \"\\n\");\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n newline(count = 1) {\r\n for (let i = 0; i < count; i++) {\r\n this.buffer.push(CMD.LF);\r\n }\r\n return this;\r\n }\r\n\r\n divider(char = \"-\", width = 32) {\r\n this.line(char.repeat(width));\r\n return this;\r\n }\r\n\r\n beep(times = 1, duration = 100) {\r\n for (let i = 0; i < times; i++) {\r\n this.buffer.push(...CMD.BEEP(duration));\r\n }\r\n return this;\r\n }\r\n\r\n drawerKick() {\r\n this.buffer.push(...CMD.DRAWER_KICK);\r\n return this;\r\n }\r\n\r\n raw(bytes) {\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n // --- Image & Thai Text Logic ---\r\n\r\n image(imageData) {\r\n const bytes = convertCanvasToEscPos(imageData);\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n /**\r\n * พิมพ์ข้อความภาษาไทย (Render เป็นรูปภาพอัตโนมัติ)\r\n *\r\n * ⚠️ REQUIRED: Sarabun font must be loaded in your HTML file:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the system will use the default font instead.\r\n *\r\n * @param {string} text - Thai text to print\r\n * @param {number} fontSize - Font size in pixels (default: 22)\r\n */\r\n printThaiText(text, fontSize = 22) {\r\n if (typeof document === \"undefined\") {\r\n console.error(\"Browser environment required for printThaiText\");\r\n return this;\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\");\r\n const ctx = canvas.getContext(\"2d\");\r\n\r\n // ตั้งค่า Font\r\n const fontFamily = \"'Sarabun', sans-serif\";\r\n const lineHeight = fontSize + 12;\r\n const lines = text.split(\"\\n\");\r\n\r\n // คำนวณความสูง\r\n const height = lines.length * lineHeight + 20;\r\n\r\n canvas.width = this.printerWidth;\r\n canvas.height = height;\r\n\r\n // วาดพื้นหลังขาว\r\n ctx.fillStyle = \"white\";\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n // วาดข้อความ\r\n ctx.fillStyle = \"black\";\r\n ctx.font = `${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = \"top\";\r\n\r\n let y = 10;\r\n for (let line of lines) {\r\n ctx.fillText(line, 10, y);\r\n y += lineHeight;\r\n }\r\n\r\n const imageData = ctx.getImageData(0, 0, this.printerWidth, height);\r\n return this.image(imageData);\r\n }\r\n\r\n // --- Execution ---\r\n\r\n clear() {\r\n this.buffer = [];\r\n return this;\r\n }\r\n\r\n getBuffer() {\r\n return new Uint8Array(this.buffer);\r\n }\r\n\r\n async print(printerName) {\r\n // ถ้าไม่ส่งชื่อมา ให้ลองดึงตัวแรก\r\n if (!printerName) {\r\n const printers = await ThermalPrinter.getPrinters(this.driverApi);\r\n if (printers.length > 0) printerName = printers[0];\r\n else throw new Error(\"No printer found.\");\r\n }\r\n\r\n try {\r\n const bufferData = this.getBuffer();\r\n const encodedName = encodeURIComponent(printerName);\r\n\r\n const res = await fetch(\r\n `${this.driverApi}/print?printer=${encodedName}`,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/octet-stream\" },\r\n body: bufferData,\r\n },\r\n );\r\n\r\n if (!res.ok) throw new Error(\"Driver Error\");\r\n\r\n this.clear();\r\n return { success: true };\r\n } catch (e) {\r\n console.error(\"Print Failed:\", e);\r\n throw e;\r\n }\r\n }\r\n\r\n // --- Static Methods ---\r\n\r\n static async getPrinters(apiUrl = \"http://localhost:9123\") {\r\n try {\r\n const res = await fetch(`${apiUrl}/printers`);\r\n return await res.json();\r\n } catch (e) {\r\n console.error(\"Connection Error:\", e);\r\n return [];\r\n }\r\n }\r\n}\r\n"],"names":["CMD","duration","convertCanvasToEscPos","imageData","width","height","pixels","xBytes","command","y","x","byte","bit","pxIndex","ThermalPrinter","driverApiUrl","alignment","cmd","enable","lines","i","partial","text","bytes","count","char","times","fontSize","canvas","ctx","fontFamily","lineHeight","line","printerName","printers","bufferData","encodedName","e","apiUrl"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"thermal-printer.umd.js","sources":["../src/constants.js","../src/utils.js","../src/index.js"],"sourcesContent":["// src/constants.js\r\nexport const CMD = {\r\n ESC: 0x1b,\r\n GS: 0x1d,\r\n LF: 0x0a,\r\n\r\n // Commands\r\n INIT: [0x1b, 0x40], // Initialize printer\r\n CUT_FULL: [0x1d, 0x56, 0x42, 0x00], // Full cut\r\n CUT_PARTIAL: [0x1d, 0x56, 0x41, 0x00], // Partial cut\r\n\r\n // Formatting\r\n BOLD_ON: [0x1b, 0x45, 0x01],\r\n BOLD_OFF: [0x1b, 0x45, 0x00],\r\n\r\n ALIGN_LEFT: [0x1b, 0x61, 0x00],\r\n ALIGN_CENTER: [0x1b, 0x61, 0x01],\r\n ALIGN_RIGHT: [0x1b, 0x61, 0x02],\r\n\r\n // Cash Drawer\r\n DRAWER_KICK: [0x1b, 0x70, 0x00, 0x0c, 0x78],\r\n\r\n // Beep (ESC B - default 100ms)\r\n BEEP: (duration = 100) => [0x1b, 0x42, duration],\r\n};\r\n","// src/utils.js\r\n\r\n/**\r\n * แปลงข้อมูลภาพ (ImageData) เป็นคำสั่ง ESC/POS GS v 0\r\n * @param {ImageData} imageData\r\n * @returns {number[]} Array ของ Byte คำสั่ง\r\n */\r\nexport function convertCanvasToEscPos(imageData) {\r\n const width = imageData.width;\r\n const height = imageData.height;\r\n const pixels = imageData.data;\r\n\r\n // 1 Byte = 8 pixels แนวนอน\r\n const xBytes = width / 8;\r\n\r\n let command = [];\r\n\r\n // Header: GS v 0 (Raster Bit Image)\r\n command.push(0x1d, 0x76, 0x30, 0x00);\r\n\r\n // บอกขนาดภาพ (Little Endian)\r\n command.push(xBytes % 256, Math.floor(xBytes / 256)); // xL, xH\r\n command.push(height % 256, Math.floor(height / 256)); // yL, yH\r\n\r\n // Loop ทุก Pixel แปลงเป็น Bit\r\n for (let y = 0; y < height; y++) {\r\n for (let x = 0; x < xBytes; x++) {\r\n let byte = 0;\r\n for (let bit = 0; bit < 8; bit++) {\r\n // คำนวณตำแหน่ง Pixel ใน Array (RGBA = 4 ช่องต่อ 1 pixel)\r\n const pxIndex = (y * width + x * 8 + bit) * 4;\r\n\r\n // เช็คความสว่าง (R+G+B)\r\n // ถ้าค่าต่ำกว่า 380 (ค่อนข้างมืด) ให้ถือเป็นสีดำ (Bit=1)\r\n const brightness =\r\n pixels[pxIndex] + pixels[pxIndex + 1] + pixels[pxIndex + 2];\r\n if (brightness < 380) {\r\n byte |= 1 << (7 - bit);\r\n }\r\n }\r\n command.push(byte);\r\n }\r\n }\r\n\r\n return command;\r\n}\r\n/**\r\n * แปลงข้อความเป็น ImageData (Client-side only)\r\n * ต้องใช้ใน Browser environment เท่านั้น\r\n *\r\n * ⚠️ REQUIRED: Sarabun font must be loaded in your HTML:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * @param {string} text - Thai text to convert\r\n * @param {number} width - Canvas width in pixels (default: 384)\r\n * @param {number} fontSize - Font size in pixels (default: 22)\r\n * @returns {ImageData} Canvas ImageData object\r\n * @throws {Error} If not in browser environment\r\n *\r\n * @example\r\n * // Client-side (React/Next.js)\r\n * const imageData = textToImageData(\"สวัสดี\", 384, 22);\r\n * await fetch('/api/print', {\r\n * body: JSON.stringify({\r\n * data: Array.from(imageData.data),\r\n * width: imageData.width,\r\n * height: imageData.height,\r\n * })\r\n * });\r\n */\r\nexport function textToImageData(text, width = 384, fontSize = 22) {\r\n // ตรวจสอบว่าเป็น Browser environment\r\n if (typeof document === \"undefined\") {\r\n throw new Error(\r\n \"textToImageData() requires browser environment with Canvas API\",\r\n );\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\");\r\n const ctx = canvas.getContext(\"2d\");\r\n\r\n // ตั้งค่า Font\r\n const fontFamily = \"'Sarabun', sans-serif\";\r\n const lineHeight = fontSize + 12;\r\n const lines = text.split(\"\\n\");\r\n\r\n // คำนวณความสูง\r\n const height = lines.length * lineHeight + 20;\r\n\r\n canvas.width = width;\r\n canvas.height = height;\r\n\r\n // วาดพื้นหลังขาว\r\n ctx.fillStyle = \"white\";\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n // วาดข้อความ\r\n ctx.fillStyle = \"black\";\r\n ctx.font = `${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = \"top\";\r\n\r\n let y = 10;\r\n for (let line of lines) {\r\n ctx.fillText(line, 10, y);\r\n y += lineHeight;\r\n }\r\n\r\n // ดึง ImageData\r\n return ctx.getImageData(0, 0, width, height);\r\n}\r\n","// src/index.js\r\nimport { CMD } from \"./constants\";\r\nimport { convertCanvasToEscPos, textToImageData } from \"./utils\";\r\n\r\n/**\r\n * Thermal Printer Library for ESC/POS printers\r\n *\r\n * IMPORTANT: When using printThaiText() or textToImageData(), you must load the Sarabun font in your HTML:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the printer will use the default system font instead of Sarabun.\r\n */\r\nexport { textToImageData } from \"./utils\";\r\nexport class ThermalPrinter {\r\n constructor(driverApiUrl = \"http://localhost:9123\", width = 384) {\r\n this.driverApi = driverApiUrl;\r\n this.printerWidth = width; // 384 dots = 58mm, 576 dots = 80mm\r\n this.buffer = [];\r\n }\r\n\r\n // --- Basic Commands ---\r\n\r\n init() {\r\n this.buffer.push(...CMD.INIT);\r\n return this;\r\n }\r\n\r\n align(alignment = 1) {\r\n // 0=Left, 1=Center, 2=Right\r\n const cmd = [...CMD.ALIGN_LEFT];\r\n cmd[2] = alignment;\r\n this.buffer.push(...cmd);\r\n return this;\r\n }\r\n\r\n bold(enable = true) {\r\n this.buffer.push(...(enable ? CMD.BOLD_ON : CMD.BOLD_OFF));\r\n return this;\r\n }\r\n\r\n feed(lines = 1) {\r\n for (let i = 0; i < lines; i++) this.buffer.push(CMD.LF);\r\n return this;\r\n }\r\n\r\n cut(partial = false) {\r\n this.buffer.push(...(partial ? CMD.CUT_PARTIAL : CMD.CUT_FULL));\r\n return this;\r\n }\r\n\r\n line(text = \"\") {\r\n const encoder = new TextEncoder();\r\n const bytes = encoder.encode(text + \"\\n\");\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n newline(count = 1) {\r\n for (let i = 0; i < count; i++) {\r\n this.buffer.push(CMD.LF);\r\n }\r\n return this;\r\n }\r\n\r\n divider(char = \"-\", width = 32) {\r\n this.line(char.repeat(width));\r\n return this;\r\n }\r\n\r\n beep(times = 1, duration = 100) {\r\n for (let i = 0; i < times; i++) {\r\n this.buffer.push(...CMD.BEEP(duration));\r\n }\r\n return this;\r\n }\r\n\r\n drawerKick() {\r\n this.buffer.push(...CMD.DRAWER_KICK);\r\n return this;\r\n }\r\n\r\n raw(bytes) {\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n // --- Image & Thai Text Logic ---\r\n\r\n image(imageData) {\r\n const bytes = convertCanvasToEscPos(imageData);\r\n this.buffer.push(...bytes);\r\n return this;\r\n }\r\n\r\n /**\r\n * พิมพ์ข้อความภาษาไทย (Render เป็นรูปภาพอัตโนมัติ)\r\n *\r\n * ⚠️ REQUIRED: Sarabun font must be loaded in your HTML file:\r\n * <link href=\"https://fonts.googleapis.com/css2?family=Sarabun:wght@400;700&display=swap\" rel=\"stylesheet\">\r\n *\r\n * Without this link, the system will use the default font instead.\r\n *\r\n * @param {string} text - Thai text to print\r\n * @param {number} fontSize - Font size in pixels (default: 22)\r\n */\r\n printThaiText(text, fontSize = 22) {\r\n if (typeof document === \"undefined\") {\r\n console.error(\"Browser environment required for printThaiText\");\r\n return this;\r\n }\r\n\r\n const canvas = document.createElement(\"canvas\");\r\n const ctx = canvas.getContext(\"2d\");\r\n\r\n // ตั้งค่า Font\r\n const fontFamily = \"'Sarabun', sans-serif\";\r\n const lineHeight = fontSize + 12;\r\n const lines = text.split(\"\\n\");\r\n\r\n // คำนวณความสูง\r\n const height = lines.length * lineHeight + 20;\r\n\r\n canvas.width = this.printerWidth;\r\n canvas.height = height;\r\n\r\n // วาดพื้นหลังขาว\r\n ctx.fillStyle = \"white\";\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n // วาดข้อความ\r\n ctx.fillStyle = \"black\";\r\n ctx.font = `${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = \"top\";\r\n\r\n let y = 10;\r\n for (let line of lines) {\r\n ctx.fillText(line, 10, y);\r\n y += lineHeight;\r\n }\r\n\r\n const imageData = ctx.getImageData(0, 0, this.printerWidth, height);\r\n return this.image(imageData);\r\n }\r\n\r\n // --- Execution ---\r\n\r\n clear() {\r\n this.buffer = [];\r\n return this;\r\n }\r\n\r\n getBuffer() {\r\n return new Uint8Array(this.buffer);\r\n }\r\n\r\n async print(printerName) {\r\n // ถ้าไม่ส่งชื่อมา ให้ลองดึงตัวแรก\r\n if (!printerName) {\r\n const printers = await ThermalPrinter.getPrinters(this.driverApi);\r\n if (printers.length > 0) printerName = printers[0];\r\n else throw new Error(\"No printer found.\");\r\n }\r\n\r\n try {\r\n const bufferData = this.getBuffer();\r\n const encodedName = encodeURIComponent(printerName);\r\n\r\n const res = await fetch(\r\n `${this.driverApi}/print?printer=${encodedName}`,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/octet-stream\" },\r\n body: bufferData,\r\n },\r\n );\r\n\r\n if (!res.ok) throw new Error(\"Driver Error\");\r\n\r\n this.clear();\r\n return { success: true };\r\n } catch (e) {\r\n console.error(\"Print Failed:\", e);\r\n throw e;\r\n }\r\n }\r\n\r\n // --- Static Methods ---\r\n\r\n static async getPrinters(apiUrl = \"http://localhost:9123\") {\r\n try {\r\n const res = await fetch(`${apiUrl}/printers`);\r\n return await res.json();\r\n } catch (e) {\r\n console.error(\"Connection Error:\", e);\r\n return [];\r\n }\r\n }\r\n}\r\n"],"names":["CMD","duration","convertCanvasToEscPos","imageData","width","height","pixels","xBytes","command","y","x","byte","bit","pxIndex","textToImageData","text","fontSize","canvas","ctx","fontFamily","lineHeight","lines","line","ThermalPrinter","driverApiUrl","alignment","cmd","enable","i","partial","bytes","count","char","times","printerName","printers","bufferData","encodedName","e","apiUrl"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naphatjm/cdh-thermal-printer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Thai Thermal Printer Library via Local Driver",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
14
15
|
"import": "./dist/thermal-printer.es.js",
|
|
15
|
-
"require": "./dist/thermal-printer.umd.js"
|
|
16
|
-
"types": "./dist/index.d.ts"
|
|
16
|
+
"require": "./dist/thermal-printer.umd.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|