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,549 @@
1
+ /**
2
+ * CPCL Driver
3
+ * PCL commands for Compact Print Language - HP/Honeywell/Toddler printers
4
+ *
5
+ * CPCL is commonly used in mobile/portable thermal printers
6
+ */
7
+
8
+ import { Logger } from '@/utils/logger';
9
+ import { Encoding } from '@/utils/encoding';
10
+
11
+ /**
12
+ * CPCL page size presets
13
+ */
14
+ export type CPCLPageSize = 'A4' | 'A5' | 'LETTER' | '4X6' | '4X2' | '4X4' | '2.25X1.25' | 'CUSTOM';
15
+
16
+ /**
17
+ * CPCL Text options
18
+ */
19
+ export interface CpclTextOptions {
20
+ /** X position in dots */
21
+ x?: number;
22
+ /** Y position in dots */
23
+ y?: number;
24
+ /** Font type: 0-6 (0=OCR, 1=OCR-B, 2=CG Triumvirate, etc.) */
25
+ font?: number;
26
+ /** Horizontal multiplier (1-8) */
27
+ xMulti?: number;
28
+ /** Vertical multiplier (1-8) */
29
+ yMulti?: number;
30
+ /** Rotation: 0, 90, 180, 270 */
31
+ rotation?: 0 | 90 | 180 | 270;
32
+ }
33
+
34
+ /**
35
+ * CPCL Barcode options
36
+ */
37
+ export interface CpclBarcodeOptions {
38
+ /** X position in dots */
39
+ x?: number;
40
+ /** Y position in dots */
41
+ y?: number;
42
+ /** Barcode type */
43
+ type:
44
+ | '128'
45
+ | '39'
46
+ | 'EAN13'
47
+ | 'EAN8'
48
+ | 'UPCA'
49
+ | 'UPCE'
50
+ | 'MSI'
51
+ | 'PLESSEY'
52
+ | 'PDF417'
53
+ | 'DATAMATRIX'
54
+ | 'QR';
55
+ /** Barcode height in dots (default: 50) */
56
+ height?: number;
57
+ /** Wide bar width for 39 (default: 2) */
58
+ wide?: number;
59
+ /** Narrow bar width (default: 1) */
60
+ narrow?: number;
61
+ /** Show human-readable text (default: true) */
62
+ readable?: boolean;
63
+ }
64
+
65
+ /**
66
+ * CPCL QR Code options
67
+ */
68
+ export interface CpclQRCodeOptions {
69
+ /** X position in dots */
70
+ x?: number;
71
+ /** Y position in dots */
72
+ y?: number;
73
+ /** Model (default: 2) */
74
+ model?: 1 | 2;
75
+ /** Error correction level: L, M, Q, H */
76
+ errorCorrection?: 'L' | 'M' | 'Q' | 'H';
77
+ /** Cell size (default: 4) */
78
+ cellSize?: number;
79
+ }
80
+
81
+ /**
82
+ * CPCL Line options
83
+ */
84
+ export interface CpclLineOptions {
85
+ /** Start X position */
86
+ x1: number;
87
+ /** Start Y position */
88
+ y1: number;
89
+ /** End X position */
90
+ x2: number;
91
+ /** End Y position */
92
+ y2: number;
93
+ /** Line width/thickness */
94
+ width?: number;
95
+ }
96
+
97
+ /**
98
+ * CPCL Box options
99
+ */
100
+ export interface CpclBoxOptions {
101
+ /** X position */
102
+ x: number;
103
+ /** Y position */
104
+ y: number;
105
+ /** Width */
106
+ width: number;
107
+ /** Height */
108
+ height: number;
109
+ /** Border thickness */
110
+ thickness?: number;
111
+ }
112
+
113
+ /**
114
+ * CPCL Driver for HP, Honeywell, and Toddler portable printers
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const cpcl = new CpclDriver();
119
+ *
120
+ * const commands = cpcl
121
+ * .pageStart()
122
+ * .text('Hello World!', { x: 50, y: 50 })
123
+ * .barcode('1234567890', { x: 50, y: 150, type: '128' })
124
+ * .qrcode('https://example.com', { x: 300, y: 50 })
125
+ * .pageEnd()
126
+ * .getCommands();
127
+ * ```
128
+ */
129
+ export class CpclDriver {
130
+ private commands: string[] = [];
131
+ private readonly logger = Logger.scope('CpclDriver');
132
+
133
+ // Page dimensions
134
+ private pageWidth = 576; // 4" at 144 DPI (common)
135
+ private pageHeight = 0; // 0 = continuous
136
+
137
+ /**
138
+ * Initialize CPCL driver
139
+ * @param width - Page width in dots
140
+ * @param height - Page height in dots (0 = continuous)
141
+ */
142
+ constructor(width = 576, height = 0) {
143
+ this.pageWidth = width;
144
+ this.pageHeight = height;
145
+ }
146
+
147
+ /**
148
+ * Set page size
149
+ * @param width - Width in dots
150
+ * @param height - Height in dots (0 = continuous)
151
+ */
152
+ setPageSize(width: number, height = 0): this {
153
+ this.pageWidth = width;
154
+ this.pageHeight = height;
155
+ return this;
156
+ }
157
+
158
+ /**
159
+ * Use standard page size
160
+ * @param size - Preset size name
161
+ */
162
+ usePageSize(size: CPCLPageSize): this {
163
+ const sizes: Record<CPCLPageSize, [number, number]> = {
164
+ '4X6': [576, 864],
165
+ '4X4': [576, 576],
166
+ '4X2': [576, 288],
167
+ '2.25X1.25': [324, 180],
168
+ A4: [992, 1406],
169
+ A5: [701, 992],
170
+ LETTER: [1050, 1500],
171
+ CUSTOM: [576, 0],
172
+ };
173
+
174
+ const [width, height] = sizes[size] || [576, 0];
175
+ this.pageWidth = width;
176
+ this.pageHeight = height;
177
+ return this;
178
+ }
179
+
180
+ /**
181
+ * Start a new page
182
+ */
183
+ pageStart(): this {
184
+ this.commands.push(`! U1 SETLP 5 0 30`);
185
+ this.commands.push(`! U1 PAGE WIDTH ${this.pageWidth}`);
186
+ if (this.pageHeight > 0) {
187
+ this.commands.push(`! U1 PAGE HEIGHT ${this.pageHeight}`);
188
+ }
189
+ this.commands.push('START');
190
+ return this;
191
+ }
192
+
193
+ /**
194
+ * End current page
195
+ */
196
+ pageEnd(): this {
197
+ this.commands.push('END');
198
+ return this;
199
+ }
200
+
201
+ /**
202
+ * Form feed to next label
203
+ */
204
+ formFeed(): this {
205
+ this.commands.push('FORM');
206
+ return this;
207
+ }
208
+
209
+ /**
210
+ * Set line print mode
211
+ * @param font - Font number (0-6)
212
+ * @param xMulti - Horizontal multiplier
213
+ * @param yMulti - Vertical multiplier
214
+ */
215
+ setLinePrint(font = 5, xMulti = 0, yMulti = 30): this {
216
+ this.commands.push(`! U1 SETLP ${font} ${xMulti} ${yMulti}`);
217
+ return this;
218
+ }
219
+
220
+ /**
221
+ * Set text font
222
+ * @param font - Font: 0=OCR, 1=OCR-B, 2=CG Triumvirate Bold, 3-6=Various sizes
223
+ * @param xMulti - Horizontal multiplier (1-8)
224
+ * @param yMulti - Vertical multiplier (1-8)
225
+ * @param rotation - Rotation angle
226
+ */
227
+ setFont(font = 3, xMulti = 1, yMulti = 1, rotation: 0 | 90 | 180 | 270 = 0): this {
228
+ const rotationMap: Record<number, string> = { 0: 'N', 90: 'R', 180: 'B', 270: 'I' };
229
+ const rot = rotationMap[rotation] || 'N';
230
+ this.commands.push(`! U1 SETLP ${font} ${xMulti} ${yMulti} ${rot}`);
231
+ return this;
232
+ }
233
+
234
+ /**
235
+ * Add text at current position
236
+ * @param content - Text content
237
+ */
238
+ text(content: string): this {
239
+ this.commands.push(`! U1 TEXT ${this.escapeText(content)}`);
240
+ return this;
241
+ }
242
+
243
+ /**
244
+ * Add positioned text
245
+ * @param content - Text content
246
+ * @param options - Text options
247
+ */
248
+ textAt(content: string, options: CpclTextOptions): this {
249
+ const { x = 0, y = 0, font = 3, xMulti = 1, yMulti = 1, rotation = 0 } = options;
250
+ const rotationMap: Record<number, string> = { 0: 'N', 90: 'R', 180: 'B', 270: 'I' };
251
+ const rot = rotationMap[rotation] || 'N';
252
+
253
+ this.commands.push(`! U1 SETLP ${font} ${xMulti} ${yMulti} ${rot}`);
254
+ this.commands.push(`! U1 ${x} ${y} TEXT ${this.escapeText(content)}`);
255
+ return this;
256
+ }
257
+
258
+ /**
259
+ * Add text using legacy command
260
+ * @param content - Text content
261
+ * @param x - X position
262
+ * @param y - Y position
263
+ * @param font - Font number
264
+ */
265
+ legacyText(content: string, x: number, y: number, font = 3): this {
266
+ this.commands.push(`TEXT ${x} ${y} ${font} "${this.escapeText(content)}"`);
267
+ return this;
268
+ }
269
+
270
+ /**
271
+ * Add barcode at position
272
+ * @param content - Barcode content
273
+ * @param options - Barcode options
274
+ */
275
+ barcode(content: string, options: CpclBarcodeOptions): this {
276
+ const {
277
+ x = 0,
278
+ y = 0,
279
+ type = '128',
280
+ height = 50,
281
+ wide = 2,
282
+ narrow = 1,
283
+ readable = true,
284
+ } = options;
285
+
286
+ const readableFlag = readable ? 'B' : 'N';
287
+
288
+ // CPCL barcode commands
289
+ switch (type) {
290
+ case '128':
291
+ this.commands.push(
292
+ `BARCODE 128 ${x} ${y} ${height} ${readableFlag} 0 ${narrow} ${wide} "${content}"`
293
+ );
294
+ break;
295
+ case '39':
296
+ this.commands.push(
297
+ `BARCODE 39 ${x} ${y} ${height} ${readableFlag} ${wide} ${narrow} "${content}"`
298
+ );
299
+ break;
300
+ case 'EAN13':
301
+ this.commands.push(`BARCODE EAN13 ${x} ${y} ${height} ${readableFlag} "${content}"`);
302
+ break;
303
+ case 'EAN8':
304
+ this.commands.push(`BARCODE EAN8 ${x} ${y} ${height} ${readableFlag} "${content}"`);
305
+ break;
306
+ case 'UPCA':
307
+ this.commands.push(`BARCODE UPCA ${x} ${y} ${height} ${readableFlag} "${content}"`);
308
+ break;
309
+ case 'UPCE':
310
+ this.commands.push(`BARCODE UPCE ${x} ${y} ${height} ${readableFlag} "${content}"`);
311
+ break;
312
+ case 'PDF417':
313
+ this.commands.push(`BARCODE PDF417 ${x} ${y} 6 200 "${content}"`);
314
+ break;
315
+ case 'DATAMATRIX':
316
+ this.commands.push(`BARCODE DATAMATRIX ${x} ${y} 200 "${content}"`);
317
+ break;
318
+ case 'QR':
319
+ // QR uses separate command
320
+ this.qrcode(content, { x, y });
321
+ break;
322
+ default:
323
+ this.commands.push(
324
+ `BARCODE 128 ${x} ${y} ${height} ${readableFlag} 0 ${narrow} ${wide} "${content}"`
325
+ );
326
+ }
327
+
328
+ return this;
329
+ }
330
+
331
+ /**
332
+ * Add Code 128 barcode (most common)
333
+ * @param content - Barcode content
334
+ * @param x - X position
335
+ * @param y - Y position
336
+ * @param height - Barcode height
337
+ */
338
+ code128(content: string, x = 0, y = 0, height = 50): this {
339
+ return this.barcode(content, { x, y, type: '128', height });
340
+ }
341
+
342
+ /**
343
+ * Add Code 39 barcode
344
+ * @param content - Barcode content
345
+ * @param x - X position
346
+ * @param y - Y position
347
+ * @param height - Barcode height
348
+ */
349
+ code39(content: string, x = 0, y = 0, height = 50): this {
350
+ return this.barcode(content, { x, y, type: '39', height, wide: 2, narrow: 1 });
351
+ }
352
+
353
+ /**
354
+ * Add QR code
355
+ * @param content - QR code content
356
+ * @param options - QR options
357
+ */
358
+ qrcode(content: string, options?: CpclQRCodeOptions): this {
359
+ const { x = 0, y = 0, model = 2, errorCorrection = 'M', cellSize = 4 } = options || {};
360
+ this.commands.push(
361
+ `BARCODE QR ${x} ${y} ${model} ${cellSize} A ${errorCorrection} "${content}"`
362
+ );
363
+ return this;
364
+ }
365
+
366
+ /**
367
+ * Add 2D barcode (PDF417 or DataMatrix)
368
+ * @param content - Content
369
+ * @param type - Type: PDF417 or DATAMATRIX
370
+ * @param x - X position
371
+ * @param y - Y position
372
+ * @param height - Height
373
+ */
374
+ twoDBarcode(content: string, type: 'PDF417' | 'DATAMATRIX', x = 0, y = 0, height = 200): this {
375
+ if (type === 'PDF417') {
376
+ this.commands.push(`BARCODE PDF417 ${x} ${y} 6 ${height} "${content}"`);
377
+ } else {
378
+ this.commands.push(`BARCODE DATAMATRIX ${x} ${y} ${height} "${content}"`);
379
+ }
380
+ return this;
381
+ }
382
+
383
+ /**
384
+ * Add line
385
+ * @param options - Line options
386
+ */
387
+ line(options: CpclLineOptions): this {
388
+ const { x1, y1, x2, y2, width = 1 } = options;
389
+ this.commands.push(`LINE ${x1} ${y1} ${x2} ${y2} ${width}`);
390
+ return this;
391
+ }
392
+
393
+ /**
394
+ * Add box/rectangle
395
+ * @param options - Box options
396
+ */
397
+ box(options: CpclBoxOptions): this {
398
+ const { x, y, width, height, thickness = 1 } = options;
399
+ this.commands.push(`BOX ${x} ${y} ${width} ${height} ${thickness}`);
400
+ return this;
401
+ }
402
+
403
+ /**
404
+ * Add inverse area (white on black)
405
+ * @param x - X position
406
+ * @param y - Y position
407
+ * @param width - Width
408
+ * @param height - Height
409
+ */
410
+ inverse(x: number, y: number, width: number, height: number): this {
411
+ this.commands.push(`INVERSE ${width} ${height} ${x} ${y}`);
412
+ return this;
413
+ }
414
+
415
+ /**
416
+ * Set print density
417
+ * @param density - Density value (-50 to +50)
418
+ */
419
+ setDensity(density: number): this {
420
+ const safeDensity = Math.min(50, Math.max(-50, density));
421
+ this.commands.push(`! U1 SETDENSITY ${safeDensity}`);
422
+ return this;
423
+ }
424
+
425
+ /**
426
+ * Set speed
427
+ * @param speed - Speed: 2-6 (2=50%, 3=75%, 4=100%, 5=125%, 6=150%)
428
+ */
429
+ setSpeed(speed: number): this {
430
+ const safeSpeed = Math.min(6, Math.max(2, speed));
431
+ this.commands.push(`! U1 SETSPEED ${safeSpeed}`);
432
+ return this;
433
+ }
434
+
435
+ /**
436
+ * Cut paper (if cutter installed)
437
+ */
438
+ cut(): this {
439
+ this.commands.push('CUT');
440
+ return this;
441
+ }
442
+
443
+ /**
444
+ * Partial cut
445
+ */
446
+ partialCut(): this {
447
+ this.commands.push('PCUT');
448
+ return this;
449
+ }
450
+
451
+ /**
452
+ * Feed and cut
453
+ */
454
+ feedCut(): this {
455
+ this.commands.push('FEED CUT');
456
+ return this;
457
+ }
458
+
459
+ /**
460
+ * Sound beep
461
+ * @param count - Number of beeps
462
+ * @param duration - Duration in 10ms units
463
+ */
464
+ beep(count = 1, duration = 5): this {
465
+ this.commands.push(`BEEP ${count} ${duration}`);
466
+ return this;
467
+ }
468
+
469
+ /**
470
+ * Add logo/image
471
+ * @param x - X position
472
+ * @param y - Y position
473
+ * @param logoName - Stored logo name
474
+ */
475
+ logo(x: number, y: number, logoName: string): this {
476
+ this.commands.push(`LOGO ${x} ${y} "${logoName}"`);
477
+ return this;
478
+ }
479
+
480
+ /**
481
+ * Download logo to printer (store in memory)
482
+ * Note: This is a placeholder for future implementation
483
+ * @param logoName - Name to store logo as
484
+ * @param _bitmap - Logo bitmap data (placeholder)
485
+ */
486
+ downloadLogo(logoName: string, _bitmap: Uint8Array): this {
487
+ this.commands.push(`! DF ${logoName}`);
488
+ // TODO: Encode bitmap to CPCL format
489
+ this.logger.debug('CPCL logo download not fully implemented');
490
+ this.commands.push(`! DF`);
491
+ return this;
492
+ }
493
+
494
+ /**
495
+ * Print stored logo
496
+ * @param logoName - Logo name
497
+ * @param x - X position
498
+ * @param y - Y position
499
+ */
500
+ printLogo(logoName: string, x = 0, y = 0): this {
501
+ this.commands.push(`LOGO ${x} ${y} "${logoName}"`);
502
+ return this;
503
+ }
504
+
505
+ /**
506
+ * Get all commands as string
507
+ */
508
+ getCommands(): string {
509
+ return this.commands.join('\r\n') + '\r\n';
510
+ }
511
+
512
+ /**
513
+ * Get commands as buffer for sending to printer
514
+ */
515
+ getBuffer(): Uint8Array {
516
+ const commandString = this.getCommands();
517
+ this.logger.debug(`CPCL commands:\n${commandString}`);
518
+ return Encoding.encode(commandString, 'ASCII');
519
+ }
520
+
521
+ /**
522
+ * Get raw command list
523
+ */
524
+ getCommandList(): string[] {
525
+ return [...this.commands];
526
+ }
527
+
528
+ /**
529
+ * Clear all commands
530
+ */
531
+ reset(): this {
532
+ this.commands = [];
533
+ return this;
534
+ }
535
+
536
+ /**
537
+ * Get page width
538
+ */
539
+ getPageWidth(): number {
540
+ return this.pageWidth;
541
+ }
542
+
543
+ /**
544
+ * Escape special characters in text
545
+ */
546
+ private escapeText(str: string): string {
547
+ return str.replace(/"/g, '""');
548
+ }
549
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * GPrinter (佳博) Driver
3
+ *
4
+ * 佳博 (GPrinter) 热敏打印机兼容 ESC/POS 指令集
5
+ * 大部分命令与标准 ESC/POS 兼容,部分特殊命令需要额外处理
6
+ */
7
+
8
+ import { EscPos, type EscPosOptions } from './EscPos';
9
+
10
+ /**
11
+ * GPrinter Driver for GiaoBao (佳博) thermal printers
12
+ *
13
+ * 佳博打印机基于 ESC/POS 指令集,此驱动扩展了标准 EscPos
14
+ * 添加了佳博特定的命令支持
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { GPrinterDriver } from 'taro-bluetooth-print';
19
+ *
20
+ * const driver = new GPrinterDriver();
21
+ * let commands = driver.init();
22
+ * commands = driver.text('Hello 佳博!', 'GBK');
23
+ * commands = driver.cut();
24
+ * ```
25
+ */
26
+
27
+ /**
28
+ * GPrinter options (same as EscPosOptions)
29
+ */
30
+ export type GPrinterOptions = EscPosOptions;
31
+
32
+ export class GPrinterDriver extends EscPos {
33
+ /**
34
+ * 佳博打印机特定: 打开钱箱
35
+ * @param pin 钱箱引脚 (0 或 1, 默认 0)
36
+ */
37
+ openCashDrawer(pin = 0): Uint8Array[] {
38
+ // ESC p m t1 t2
39
+ // m = 0 or 1 (pin)
40
+ // t1 = 50 (on time)
41
+ // t2 = 200 (off time)
42
+ return [new Uint8Array([0x1b, 0x70, pin, 50, 200])];
43
+ }
44
+
45
+ /**
46
+ * 佳博打印机特定: 发送声响
47
+ * @param times 次数 (1-9)
48
+ * @param duration 持续时间
49
+ */
50
+ beep(times = 3, duration = 50): Uint8Array[] {
51
+ // ESC B n t
52
+ return [new Uint8Array([0x1b, 0x42, times, duration])];
53
+ }
54
+
55
+ /**
56
+ * 佳博打印机特定: 打印自检页
57
+ */
58
+ selfTest(): Uint8Array[] {
59
+ // ESC i
60
+ return [new Uint8Array([0x1b, 0x69])];
61
+ }
62
+
63
+ /**
64
+ * 佳博打印机特定: 获取状态
65
+ * 返回打印机状态字节
66
+ */
67
+ getStatus(): Uint8Array[] {
68
+ // DLE EOT n (n = 1-4 获取不同状态)
69
+ // 状态 1: 打印机状态
70
+ // 状态 2: 脱机状态
71
+ // 状态 3: 错误状态
72
+ // 状态 4: 纸张状态
73
+ const buffers: Uint8Array[] = [];
74
+ for (let i = 1; i <= 4; i++) {
75
+ buffers.push(new Uint8Array([0x10, 0x04, i]));
76
+ }
77
+ return buffers;
78
+ }
79
+
80
+ /**
81
+ * 佳博打印机特定: 设置字符代码页
82
+ * @param codePage 代码页编号
83
+ */
84
+ setCodePage(codePage: number): Uint8Array[] {
85
+ // ESC t n
86
+ return [new Uint8Array([0x1b, 0x74, codePage])];
87
+ }
88
+
89
+ /**
90
+ * 佳博打印机特定: 打印并走纸
91
+ * @param lines 走纸行数
92
+ */
93
+ printAndFeed(lines: number): Uint8Array[] {
94
+ // ESC d n
95
+ return [new Uint8Array([0x1b, 0x64, lines])];
96
+ }
97
+
98
+ /**
99
+ * 佳博打印机特定: 设置左边界
100
+ * @param n 左边界字符数
101
+ */
102
+ setLeftMargin(n: number): Uint8Array[] {
103
+ // ESC l n
104
+ return [new Uint8Array([0x1b, 0x6c, n])];
105
+ }
106
+
107
+ /**
108
+ * 佳博打印机特定: 设置打印区域宽度
109
+ * @param n 宽度 (字符数)
110
+ */
111
+ setPrintWidth(n: number): Uint8Array[] {
112
+ // ESC W n
113
+ return [new Uint8Array([0x1b, 0x57, n])];
114
+ }
115
+ }