taro-bluetooth-print 2.2.1 → 2.3.1

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +57 -165
  2. package/README.md +142 -285
  3. package/dist/index.cjs.js +1 -1
  4. package/dist/index.es.js +1 -81644
  5. package/dist/index.umd.js +1 -1
  6. package/dist/types/adapters/AdapterFactory.d.ts +0 -1
  7. package/dist/types/adapters/AlipayAdapter.d.ts +0 -1
  8. package/dist/types/adapters/BaiduAdapter.d.ts +0 -1
  9. package/dist/types/adapters/BaseAdapter.d.ts +0 -1
  10. package/dist/types/adapters/ByteDanceAdapter.d.ts +0 -1
  11. package/dist/types/adapters/TaroAdapter.d.ts +0 -1
  12. package/dist/types/adapters/WebBluetoothAdapter.d.ts +0 -1
  13. package/dist/types/config/PrinterConfig.d.ts +0 -1
  14. package/dist/types/core/BluetoothPrinter.d.ts +1 -2
  15. package/dist/types/core/EventEmitter.d.ts +6 -26
  16. package/dist/types/core/index.d.ts +6 -0
  17. package/dist/types/drivers/CpclDriver.d.ts +304 -0
  18. package/dist/types/drivers/EscPos.d.ts +0 -1
  19. package/dist/types/drivers/GPrinterDriver.d.ts +63 -0
  20. package/dist/types/drivers/TsplDriver.d.ts +251 -0
  21. package/dist/types/drivers/ZplDriver.d.ts +325 -0
  22. package/dist/types/drivers/index.d.ts +9 -0
  23. package/dist/types/encoding/gbk-lite.d.ts +8 -0
  24. package/dist/types/encoding/gbk-table.d.ts +8 -30
  25. package/dist/types/index.d.ts +10 -5
  26. package/dist/types/plugins/PluginManager.d.ts +87 -0
  27. package/dist/types/plugins/builtin/LoggingPlugin.d.ts +14 -0
  28. package/dist/types/plugins/builtin/RetryPlugin.d.ts +18 -0
  29. package/dist/types/plugins/index.d.ts +7 -0
  30. package/dist/types/plugins/types.d.ts +97 -0
  31. package/dist/types/services/CommandBuilder.d.ts +0 -1
  32. package/dist/types/services/ConnectionManager.d.ts +1 -2
  33. package/dist/types/services/PrintJobManager.d.ts +0 -1
  34. package/dist/types/services/index.d.ts +8 -0
  35. package/dist/types/services/interfaces/index.d.ts +0 -1
  36. package/dist/types/template/TemplateEngine.d.ts +0 -1
  37. package/package.json +36 -20
  38. package/src/adapters/BaseAdapter.ts +6 -8
  39. package/src/core/BluetoothPrinter.ts +15 -15
  40. package/src/core/EventEmitter.ts +15 -15
  41. package/src/core/index.ts +7 -0
  42. package/src/drivers/CpclDriver.ts +549 -0
  43. package/src/drivers/GPrinterDriver.ts +115 -0
  44. package/src/drivers/TsplDriver.ts +405 -0
  45. package/src/drivers/ZplDriver.ts +543 -0
  46. package/src/drivers/index.ts +37 -0
  47. package/src/encoding/gbk-lite.ts +108 -0
  48. package/src/encoding/gbk-table.ts +80 -58
  49. package/src/index.ts +27 -23
  50. package/src/plugins/PluginManager.ts +195 -0
  51. package/src/plugins/builtin/LoggingPlugin.ts +99 -0
  52. package/src/plugins/builtin/RetryPlugin.ts +103 -0
  53. package/src/plugins/index.ts +10 -0
  54. package/src/plugins/types.ts +119 -0
  55. package/src/services/ConnectionManager.ts +22 -22
  56. package/src/services/index.ts +16 -0
@@ -0,0 +1,405 @@
1
+ /**
2
+ * TSPL Driver
3
+ * TSC Printer Language driver for label/barcode printers
4
+ *
5
+ * TSPL is commonly used in thermal transfer label printers (TSC, Zebra, etc.)
6
+ */
7
+
8
+ import { Logger } from '@/utils/logger';
9
+ import { Encoding } from '@/utils/encoding';
10
+
11
+ /**
12
+ * Label size configuration
13
+ */
14
+ export interface LabelSize {
15
+ /** Label width in mm */
16
+ width: number;
17
+ /** Label height in mm */
18
+ height: number;
19
+ /** Gap between labels in mm (default: 3) */
20
+ gap?: number;
21
+ }
22
+
23
+ /**
24
+ * Text position and style
25
+ */
26
+ export interface TextOptions {
27
+ /** X position in dots */
28
+ x: number;
29
+ /** Y position in dots */
30
+ y: number;
31
+ /** Font size (1-8, default: 2) */
32
+ font?: number;
33
+ /** Rotation (0, 90, 180, 270, default: 0) */
34
+ rotation?: 0 | 90 | 180 | 270;
35
+ /** Horizontal multiplier (1-10, default: 1) */
36
+ xMultiplier?: number;
37
+ /** Vertical multiplier (1-10, default: 1) */
38
+ yMultiplier?: number;
39
+ }
40
+
41
+ /**
42
+ * Barcode options
43
+ */
44
+ export interface BarcodeOptions {
45
+ /** X position in dots */
46
+ x: number;
47
+ /** Y position in dots */
48
+ y: number;
49
+ /** Barcode type */
50
+ type: '128' | '39' | 'EAN13' | 'EAN8' | 'UPCA' | 'QRCODE';
51
+ /** Height in dots (default: 100) */
52
+ height?: number;
53
+ /** Narrow bar width (default: 2) */
54
+ narrow?: number;
55
+ /** Wide bar width (default: 4) */
56
+ wide?: number;
57
+ /** Show human-readable text (default: true) */
58
+ showText?: boolean;
59
+ /** Rotation (0, 90, 180, 270, default: 0) */
60
+ rotation?: 0 | 90 | 180 | 270;
61
+ }
62
+
63
+ /**
64
+ * QR Code options
65
+ */
66
+ export interface QRCodeOptions {
67
+ /** X position in dots */
68
+ x: number;
69
+ /** Y position in dots */
70
+ y: number;
71
+ /** Error correction level (L, M, Q, H, default: M) */
72
+ eccLevel?: 'L' | 'M' | 'Q' | 'H';
73
+ /** Cell width (1-10, default: 6) */
74
+ cellWidth?: number;
75
+ /** Mode (A=Auto, M=Manual, default: A) */
76
+ mode?: 'A' | 'M';
77
+ /** Rotation (0, 90, 180, 270, default: 0) */
78
+ rotation?: 0 | 90 | 180 | 270;
79
+ }
80
+
81
+ /**
82
+ * Box/Rectangle options
83
+ */
84
+ export interface BoxOptions {
85
+ /** X position in dots */
86
+ x: number;
87
+ /** Y position in dots */
88
+ y: number;
89
+ /** Width in dots */
90
+ width: number;
91
+ /** Height in dots */
92
+ height: number;
93
+ /** Line thickness (default: 2) */
94
+ thickness?: number;
95
+ }
96
+
97
+ /**
98
+ * Line options
99
+ */
100
+ export interface LineOptions {
101
+ /** Start X position in dots */
102
+ x1: number;
103
+ /** Start Y position in dots */
104
+ y1: number;
105
+ /** End X position in dots */
106
+ x2: number;
107
+ /** End Y position in dots */
108
+ y2: number;
109
+ /** Line thickness (default: 2) */
110
+ thickness?: number;
111
+ }
112
+
113
+ /**
114
+ * TSPL Driver for label printers
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const tspl = new TsplDriver();
119
+ *
120
+ * const commands = tspl
121
+ * .size(60, 40)
122
+ * .gap(3)
123
+ * .clear()
124
+ * .text('Product Name', { x: 50, y: 50, font: 3 })
125
+ * .barcode('1234567890', { x: 50, y: 100, type: '128' })
126
+ * .print(1)
127
+ * .getBuffer();
128
+ * ```
129
+ */
130
+ export class TsplDriver {
131
+ private commands: string[] = [];
132
+ private readonly logger = Logger.scope('TsplDriver');
133
+ private dpi = 203; // Default DPI for most label printers
134
+
135
+ /**
136
+ * Set printer DPI (dots per inch)
137
+ * @param dpi - DPI value (203 or 300)
138
+ */
139
+ setDPI(dpi: 203 | 300): this {
140
+ this.dpi = dpi;
141
+ return this;
142
+ }
143
+
144
+ /**
145
+ * Convert mm to dots
146
+ */
147
+ mmToDots(mm: number): number {
148
+ return Math.round((mm * this.dpi) / 25.4);
149
+ }
150
+
151
+ /**
152
+ * Convert dots to mm
153
+ */
154
+ dotsToMm(dots: number): number {
155
+ return (dots * 25.4) / this.dpi;
156
+ }
157
+
158
+ /**
159
+ * Set label size
160
+ * @param width - Label width in mm
161
+ * @param height - Label height in mm
162
+ */
163
+ size(width: number, height: number): this {
164
+ this.commands.push(`SIZE ${width} mm, ${height} mm`);
165
+ return this;
166
+ }
167
+
168
+ /**
169
+ * Set gap between labels
170
+ * @param gap - Gap size in mm
171
+ * @param offset - Offset in mm (default: 0)
172
+ */
173
+ gap(gap: number, offset = 0): this {
174
+ this.commands.push(`GAP ${gap} mm, ${offset} mm`);
175
+ return this;
176
+ }
177
+
178
+ /**
179
+ * Set print speed
180
+ * @param speed - Speed level (1-10)
181
+ */
182
+ speed(speed: number): this {
183
+ this.commands.push(`SPEED ${Math.min(10, Math.max(1, speed))}`);
184
+ return this;
185
+ }
186
+
187
+ /**
188
+ * Set print density
189
+ * @param density - Density level (0-15)
190
+ */
191
+ density(density: number): this {
192
+ this.commands.push(`DENSITY ${Math.min(15, Math.max(0, density))}`);
193
+ return this;
194
+ }
195
+
196
+ /**
197
+ * Set print direction
198
+ * @param direction - 0=normal, 1=reversed
199
+ */
200
+ direction(direction: 0 | 1): this {
201
+ this.commands.push(`DIRECTION ${direction}`);
202
+ return this;
203
+ }
204
+
205
+ /**
206
+ * Clear image buffer
207
+ */
208
+ clear(): this {
209
+ this.commands.push('CLS');
210
+ return this;
211
+ }
212
+
213
+ /**
214
+ * Add text to label
215
+ * @param content - Text content
216
+ * @param options - Text options
217
+ */
218
+ text(content: string, options: TextOptions): this {
219
+ const { x, y, font = 2, rotation = 0, xMultiplier = 1, yMultiplier = 1 } = options;
220
+
221
+ // TEXT x, y, "font", rotation, x-mul, y-mul, "content"
222
+ this.commands.push(
223
+ `TEXT ${x},${y},"${font}",${rotation},${xMultiplier},${yMultiplier},"${this.escapeString(content)}"`
224
+ );
225
+ return this;
226
+ }
227
+
228
+ /**
229
+ * Add barcode to label
230
+ * @param content - Barcode content
231
+ * @param options - Barcode options
232
+ */
233
+ barcode(content: string, options: BarcodeOptions): this {
234
+ const {
235
+ x,
236
+ y,
237
+ type,
238
+ height = 100,
239
+ narrow = 2,
240
+ wide = 4,
241
+ showText = true,
242
+ rotation = 0,
243
+ } = options;
244
+
245
+ const readable = showText ? 1 : 0;
246
+
247
+ if (type === 'QRCODE') {
248
+ // Use QRCODE command instead
249
+ return this.qrcode(content, { x, y, rotation });
250
+ }
251
+
252
+ // BARCODE x, y, "type", height, readable, rotation, narrow, wide, "content"
253
+ this.commands.push(
254
+ `BARCODE ${x},${y},"${type}",${height},${readable},${rotation},${narrow},${wide},"${content}"`
255
+ );
256
+ return this;
257
+ }
258
+
259
+ /**
260
+ * Add QR code to label
261
+ * @param content - QR code content
262
+ * @param options - QR code options
263
+ */
264
+ qrcode(content: string, options: QRCodeOptions): this {
265
+ const { x, y, eccLevel = 'M', cellWidth = 6, mode = 'A', rotation = 0 } = options;
266
+
267
+ // QRCODE x, y, ECC level, cell width, mode, rotation, "content"
268
+ this.commands.push(
269
+ `QRCODE ${x},${y},${eccLevel},${cellWidth},${mode},${rotation},"${this.escapeString(content)}"`
270
+ );
271
+ return this;
272
+ }
273
+
274
+ /**
275
+ * Draw a box/rectangle
276
+ * @param options - Box options
277
+ */
278
+ box(options: BoxOptions): this {
279
+ const { x, y, width, height, thickness = 2 } = options;
280
+ this.commands.push(`BOX ${x},${y},${x + width},${y + height},${thickness}`);
281
+ return this;
282
+ }
283
+
284
+ /**
285
+ * Draw a line
286
+ * @param options - Line options
287
+ */
288
+ line(options: LineOptions): this {
289
+ const { x1, y1, x2, y2, thickness = 2 } = options;
290
+
291
+ if (x1 === x2 || y1 === y2) {
292
+ // Horizontal or vertical line - use BAR command
293
+ const width = Math.abs(x2 - x1) || thickness;
294
+ const height = Math.abs(y2 - y1) || thickness;
295
+ this.commands.push(`BAR ${Math.min(x1, x2)},${Math.min(y1, y2)},${width},${height}`);
296
+ } else {
297
+ // Diagonal line - use DIAGONAL command if supported
298
+ this.commands.push(
299
+ `DIAGONAL ${x1},${y1},${thickness},${Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)},${(Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI}`
300
+ );
301
+ }
302
+ return this;
303
+ }
304
+
305
+ /**
306
+ * Fill a rectangular area
307
+ * @param x - X position
308
+ * @param y - Y position
309
+ * @param width - Width
310
+ * @param height - Height
311
+ */
312
+ bar(x: number, y: number, width: number, height: number): this {
313
+ this.commands.push(`BAR ${x},${y},${width},${height}`);
314
+ return this;
315
+ }
316
+
317
+ /**
318
+ * Reverse a rectangular area (white becomes black and vice versa)
319
+ * @param x - X position
320
+ * @param y - Y position
321
+ * @param width - Width
322
+ * @param height - Height
323
+ */
324
+ reverse(x: number, y: number, width: number, height: number): this {
325
+ this.commands.push(`REVERSE ${x},${y},${width},${height}`);
326
+ return this;
327
+ }
328
+
329
+ /**
330
+ * Print the label
331
+ * @param copies - Number of copies (default: 1)
332
+ * @param sets - Number of sets (default: 1)
333
+ */
334
+ print(copies = 1, sets = 1): this {
335
+ this.commands.push(`PRINT ${copies},${sets}`);
336
+ return this;
337
+ }
338
+
339
+ /**
340
+ * Feed labels
341
+ * @param count - Number of labels to feed
342
+ */
343
+ feed(count = 1): this {
344
+ this.commands.push(`FORMFEED`);
345
+ for (let i = 1; i < count; i++) {
346
+ this.commands.push(`FORMFEED`);
347
+ }
348
+ return this;
349
+ }
350
+
351
+ /**
352
+ * Cut paper (if cutter available)
353
+ */
354
+ cut(): this {
355
+ this.commands.push('CUT');
356
+ return this;
357
+ }
358
+
359
+ /**
360
+ * Beep the buzzer
361
+ */
362
+ beep(): this {
363
+ this.commands.push('BEEP');
364
+ return this;
365
+ }
366
+
367
+ /**
368
+ * Home the print head
369
+ */
370
+ home(): this {
371
+ this.commands.push('HOME');
372
+ return this;
373
+ }
374
+
375
+ /**
376
+ * Escape special characters in string
377
+ */
378
+ private escapeString(str: string): string {
379
+ return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
380
+ }
381
+
382
+ /**
383
+ * Get all commands as string
384
+ */
385
+ getCommands(): string {
386
+ return this.commands.join('\r\n') + '\r\n';
387
+ }
388
+
389
+ /**
390
+ * Get commands as buffer for sending to printer
391
+ */
392
+ getBuffer(): Uint8Array {
393
+ const commandString = this.getCommands();
394
+ this.logger.debug(`TSPL commands:\n${commandString}`);
395
+ return Encoding.encode(commandString, 'ASCII');
396
+ }
397
+
398
+ /**
399
+ * Clear all commands
400
+ */
401
+ reset(): this {
402
+ this.commands = [];
403
+ return this;
404
+ }
405
+ }