taro-bluetooth-print 2.2.0 → 2.3.0

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 (49) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +128 -22
  3. package/dist/index.cjs.js +1 -1
  4. package/dist/index.es.js +1 -6995
  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 +6 -34
  8. package/dist/types/adapters/BaiduAdapter.d.ts +6 -34
  9. package/dist/types/adapters/BaseAdapter.d.ts +112 -1
  10. package/dist/types/adapters/ByteDanceAdapter.d.ts +6 -34
  11. package/dist/types/adapters/TaroAdapter.d.ts +6 -34
  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 +0 -1
  15. package/dist/types/drivers/EscPos.d.ts +0 -1
  16. package/dist/types/drivers/TsplDriver.d.ts +251 -0
  17. package/dist/types/encoding/gbk-data.d.ts +12 -0
  18. package/dist/types/encoding/gbk-table.d.ts +5 -1
  19. package/dist/types/index.d.ts +5 -0
  20. package/dist/types/plugins/PluginManager.d.ts +87 -0
  21. package/dist/types/plugins/builtin/LoggingPlugin.d.ts +14 -0
  22. package/dist/types/plugins/builtin/RetryPlugin.d.ts +18 -0
  23. package/dist/types/plugins/index.d.ts +7 -0
  24. package/dist/types/plugins/types.d.ts +97 -0
  25. package/dist/types/services/CommandBuilder.d.ts +6 -1
  26. package/dist/types/services/ConnectionManager.d.ts +0 -1
  27. package/dist/types/services/PrintJobManager.d.ts +6 -2
  28. package/dist/types/services/interfaces/index.d.ts +0 -1
  29. package/dist/types/template/TemplateEngine.d.ts +0 -1
  30. package/package.json +16 -18
  31. package/src/adapters/AlipayAdapter.ts +8 -314
  32. package/src/adapters/BaiduAdapter.ts +8 -312
  33. package/src/adapters/BaseAdapter.ts +366 -0
  34. package/src/adapters/ByteDanceAdapter.ts +8 -316
  35. package/src/adapters/TaroAdapter.ts +8 -367
  36. package/src/core/EventEmitter.ts +9 -6
  37. package/src/drivers/TsplDriver.ts +417 -0
  38. package/src/encoding/gbk-data.ts +1911 -0
  39. package/src/encoding/gbk-table.ts +22 -498
  40. package/src/index.ts +14 -0
  41. package/src/plugins/PluginManager.ts +193 -0
  42. package/src/plugins/builtin/LoggingPlugin.ts +97 -0
  43. package/src/plugins/builtin/RetryPlugin.ts +109 -0
  44. package/src/plugins/index.ts +10 -0
  45. package/src/plugins/types.ts +119 -0
  46. package/src/preview/PreviewRenderer.ts +7 -1
  47. package/src/queue/PrintQueue.ts +10 -6
  48. package/src/services/CommandBuilder.ts +30 -0
  49. package/src/services/PrintJobManager.ts +51 -35
@@ -0,0 +1,417 @@
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 {
220
+ x,
221
+ y,
222
+ font = 2,
223
+ rotation = 0,
224
+ xMultiplier = 1,
225
+ yMultiplier = 1,
226
+ } = options;
227
+
228
+ // TEXT x, y, "font", rotation, x-mul, y-mul, "content"
229
+ this.commands.push(
230
+ `TEXT ${x},${y},"${font}",${rotation},${xMultiplier},${yMultiplier},"${this.escapeString(content)}"`
231
+ );
232
+ return this;
233
+ }
234
+
235
+ /**
236
+ * Add barcode to label
237
+ * @param content - Barcode content
238
+ * @param options - Barcode options
239
+ */
240
+ barcode(content: string, options: BarcodeOptions): this {
241
+ const {
242
+ x,
243
+ y,
244
+ type,
245
+ height = 100,
246
+ narrow = 2,
247
+ wide = 4,
248
+ showText = true,
249
+ rotation = 0,
250
+ } = options;
251
+
252
+ const readable = showText ? 1 : 0;
253
+
254
+ if (type === 'QRCODE') {
255
+ // Use QRCODE command instead
256
+ return this.qrcode(content, { x, y, rotation });
257
+ }
258
+
259
+ // BARCODE x, y, "type", height, readable, rotation, narrow, wide, "content"
260
+ this.commands.push(
261
+ `BARCODE ${x},${y},"${type}",${height},${readable},${rotation},${narrow},${wide},"${content}"`
262
+ );
263
+ return this;
264
+ }
265
+
266
+ /**
267
+ * Add QR code to label
268
+ * @param content - QR code content
269
+ * @param options - QR code options
270
+ */
271
+ qrcode(content: string, options: QRCodeOptions): this {
272
+ const {
273
+ x,
274
+ y,
275
+ eccLevel = 'M',
276
+ cellWidth = 6,
277
+ mode = 'A',
278
+ rotation = 0,
279
+ } = options;
280
+
281
+ // QRCODE x, y, ECC level, cell width, mode, rotation, "content"
282
+ this.commands.push(
283
+ `QRCODE ${x},${y},${eccLevel},${cellWidth},${mode},${rotation},"${this.escapeString(content)}"`
284
+ );
285
+ return this;
286
+ }
287
+
288
+ /**
289
+ * Draw a box/rectangle
290
+ * @param options - Box options
291
+ */
292
+ box(options: BoxOptions): this {
293
+ const { x, y, width, height, thickness = 2 } = options;
294
+ this.commands.push(`BOX ${x},${y},${x + width},${y + height},${thickness}`);
295
+ return this;
296
+ }
297
+
298
+ /**
299
+ * Draw a line
300
+ * @param options - Line options
301
+ */
302
+ line(options: LineOptions): this {
303
+ const { x1, y1, x2, y2, thickness = 2 } = options;
304
+
305
+ if (x1 === x2 || y1 === y2) {
306
+ // Horizontal or vertical line - use BAR command
307
+ const width = Math.abs(x2 - x1) || thickness;
308
+ const height = Math.abs(y2 - y1) || thickness;
309
+ this.commands.push(`BAR ${Math.min(x1, x2)},${Math.min(y1, y2)},${width},${height}`);
310
+ } else {
311
+ // Diagonal line - use DIAGONAL command if supported
312
+ this.commands.push(`DIAGONAL ${x1},${y1},${thickness},${Math.sqrt((x2-x1)**2 + (y2-y1)**2)},${Math.atan2(y2-y1, x2-x1) * 180 / Math.PI}`);
313
+ }
314
+ return this;
315
+ }
316
+
317
+ /**
318
+ * Fill a rectangular area
319
+ * @param x - X position
320
+ * @param y - Y position
321
+ * @param width - Width
322
+ * @param height - Height
323
+ */
324
+ bar(x: number, y: number, width: number, height: number): this {
325
+ this.commands.push(`BAR ${x},${y},${width},${height}`);
326
+ return this;
327
+ }
328
+
329
+ /**
330
+ * Reverse a rectangular area (white becomes black and vice versa)
331
+ * @param x - X position
332
+ * @param y - Y position
333
+ * @param width - Width
334
+ * @param height - Height
335
+ */
336
+ reverse(x: number, y: number, width: number, height: number): this {
337
+ this.commands.push(`REVERSE ${x},${y},${width},${height}`);
338
+ return this;
339
+ }
340
+
341
+ /**
342
+ * Print the label
343
+ * @param copies - Number of copies (default: 1)
344
+ * @param sets - Number of sets (default: 1)
345
+ */
346
+ print(copies = 1, sets = 1): this {
347
+ this.commands.push(`PRINT ${copies},${sets}`);
348
+ return this;
349
+ }
350
+
351
+ /**
352
+ * Feed labels
353
+ * @param count - Number of labels to feed
354
+ */
355
+ feed(count = 1): this {
356
+ this.commands.push(`FORMFEED`);
357
+ for (let i = 1; i < count; i++) {
358
+ this.commands.push(`FORMFEED`);
359
+ }
360
+ return this;
361
+ }
362
+
363
+ /**
364
+ * Cut paper (if cutter available)
365
+ */
366
+ cut(): this {
367
+ this.commands.push('CUT');
368
+ return this;
369
+ }
370
+
371
+ /**
372
+ * Beep the buzzer
373
+ */
374
+ beep(): this {
375
+ this.commands.push('BEEP');
376
+ return this;
377
+ }
378
+
379
+ /**
380
+ * Home the print head
381
+ */
382
+ home(): this {
383
+ this.commands.push('HOME');
384
+ return this;
385
+ }
386
+
387
+ /**
388
+ * Escape special characters in string
389
+ */
390
+ private escapeString(str: string): string {
391
+ return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
392
+ }
393
+
394
+ /**
395
+ * Get all commands as string
396
+ */
397
+ getCommands(): string {
398
+ return this.commands.join('\r\n') + '\r\n';
399
+ }
400
+
401
+ /**
402
+ * Get commands as buffer for sending to printer
403
+ */
404
+ getBuffer(): Uint8Array {
405
+ const commandString = this.getCommands();
406
+ this.logger.debug(`TSPL commands:\n${commandString}`);
407
+ return Encoding.encode(commandString, 'ASCII');
408
+ }
409
+
410
+ /**
411
+ * Clear all commands
412
+ */
413
+ reset(): this {
414
+ this.commands = [];
415
+ return this;
416
+ }
417
+ }