tauri-plugin-thermal-printer 1.0.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.
package/README.md ADDED
@@ -0,0 +1,1252 @@
1
+ # Tauri Plugin thermal-printer
2
+
3
+ This plugin provides thermal printer functionality for Tauri applications, allowing you to print documents, test printers, and list available printers.
4
+
5
+ | Platform | Supported |
6
+ | -------- | --------- |
7
+ | Linux | ✅ |
8
+ | macOS | ✅ |
9
+ | Windows | ✅ |
10
+ | Android | ❌ |
11
+ | iOS | ❌ |
12
+
13
+ For mobile applications, this plugin is currently working on this...
14
+
15
+ ## Table of Contents
16
+
17
+ - [How it Works](#how-it-works)
18
+ - [Installation](#installation)
19
+ - [Rust](#rust)
20
+ - [Bun / NPM / PNPM](#bun--npm--pnpm)
21
+ - [lib.rs](#librs)
22
+ - [Permission](#permission)
23
+ - [Functions](#functions)
24
+ - [List Printers](#list-printers)
25
+ - [Test Printer](#test-printer)
26
+ - [Print Document](#print-document)
27
+ - [Section Types](#section-types)
28
+ - [Title](#title)
29
+ - [Subtitle](#subtitle)
30
+ - [Text](#text)
31
+ - [Feed](#feed)
32
+ - [Cut](#cut)
33
+ - [Beep](#beep)
34
+ - [Drawer](#drawer)
35
+ - [Qr](#qr)
36
+ - [Barcode](#barcode)
37
+ - [Table](#table)
38
+ - [DataMatrix](#datamatrix)
39
+ - [Pdf417](#pdf417)
40
+ - [Image](#Image)
41
+ - [Logo](#logo)
42
+ - [Line](#line)
43
+ - [GlobalStyles](#globalstyles)
44
+ - [Examples](#examples)
45
+
46
+ ## How it Works
47
+
48
+ This plugin acts as a **translator** between a user-friendly JavaScript/TypeScript API and the low-level ESC/POS binary commands that thermal printers understand.
49
+
50
+ ### Architecture
51
+
52
+ ```
53
+ Frontend (JavaScript/TypeScript)
54
+ ↓ (IPC Commands)
55
+ Tauri Core (Rust)
56
+ ↓ (Platform-specific implementations)
57
+ Operating System (Linux/macOS/Windows)
58
+ ↓ (Raw binary data)
59
+ Thermal Printer (ESC/POS protocol)
60
+ ```
61
+
62
+ ### Core Components
63
+
64
+ #### 1. **Data Models** (`src/models/`)
65
+ - **`PrintJobRequest`**: Main structure defining a print job
66
+ - **`PrintSections`**: Enum with all printable content types (Title, Text, Table, QR, etc.)
67
+ - **`GlobalStyles`**: Formatting styles (bold, alignment, size, etc.)
68
+
69
+ #### 2. **Tauri Commands** (`src/commands.rs`)
70
+ Three main functions exposed to the frontend:
71
+ - `list_thermal_printers()`: Lists available printers
72
+ - `print_thermal_printer()`: Prints a document
73
+ - `test_thermal_printer()`: Runs functionality tests
74
+
75
+ #### 3. **Print Processing** (`src/process/process_print.rs`)
76
+ Converts data structures into ESC/POS binary commands:
77
+ ```rust
78
+ pub fn generate_document(&mut self, print_job: &PrintJobRequest) -> Result<Vec<u8>, String>
79
+ ```
80
+
81
+ #### 4. **OS Integration** (`src/desktop_printers/`)
82
+ - **Linux/macOS**: Uses CUPS system (`lpstat`, `lp` commands)
83
+ - **Windows**: Uses WinAPI (Windows API) to directly access system printers via functions such as EnumPrintersW for listing printers, OpenPrinterW for opening printer handles, and WritePrinter for sending raw data
84
+ - **Android**: Basic structure present, not yet implemented
85
+
86
+ ### Workflow
87
+
88
+ #### Printing a Document:
89
+
90
+ 1. **Frontend** sends `PrintJobRequest` with sections and configuration
91
+ 2. **Tauri** receives the command and processes it in Rust
92
+ 3. **`ProcessPrint`** converts each section into ESC/POS commands
93
+ 4. **Operating System** sends binary data to the printer
94
+ 5. **Thermal Printer** interprets ESC/POS commands and prints
95
+
96
+ #### Print Structure Example:
97
+ ```json
98
+ {
99
+ "printer": "TM-T20II",
100
+ "paper_size": "Mm80",
101
+ "options": {
102
+ "cut_paper": true,
103
+ "beep": false
104
+ },
105
+ "sections": [
106
+ {"Title": {"text": "My Title"}},
107
+ {"Text": {"text": "Normal content"}},
108
+ {"Table": {"columns": 3, "body": [["A", "B", "C"]]}}
109
+ ]
110
+ }
111
+ ```
112
+
113
+ ### ESC/POS Protocol
114
+
115
+ The plugin translates all sections into **ESC/POS** (Escape Sequence for Point of Sale) commands, the de facto standard for thermal printers:
116
+
117
+ - `\x1B\x40` - Initialize printer
118
+ - `\x1B\x61\x01` - Center text
119
+ - `\x1B\x45\x01` - Enable bold
120
+ - etc.
121
+
122
+ ### Supported Content Types
123
+
124
+ - **Text**: Title, Subtitle, Text with optional styles
125
+ - **Codes**: QR, Barcode, DataMatrix, PDF417
126
+ - **Media**: Images, Logos
127
+ - **Control**: Feed, Cut, Beep, Cash Drawer
128
+ - **Tables**: Configurable columns
129
+ - **Lines**: Horizontal separators
130
+
131
+ ### Platform Status
132
+
133
+ - ✅ **Linux**: Fully functional (CUPS)
134
+ - ✅ **macOS**: Fully functional (CUPS)
135
+ - ✅ **Windows**: Fully functional (WinAPI)
136
+ - ❌ **Android**: Basic structure present, not implemented
137
+ - ❌ **iOS**: Not implemented
138
+
139
+ ### Supported Connections
140
+
141
+ - **USB**: Direct USB port connection
142
+ - **Network**: TCP/IP (port 9100 typical)
143
+ - **Serial**: RS-232 (less common)
144
+ - **Bluetooth**: For Android (when implemented)
145
+
146
+ ## Installation
147
+
148
+ ### Rust
149
+
150
+ ```bash
151
+ cargo add tauri-plugin-thermal-printer
152
+ ```
153
+
154
+ ```toml
155
+ [dependencies]
156
+ tauri-plugin-thermal-printer = "version"
157
+ ```
158
+
159
+ ### Bun / NPM / PNPM
160
+
161
+ ```bash
162
+ # it's not published yet
163
+ ```
164
+
165
+ This library not only contains the connector to the backend. Also adds the types for the print structure...
166
+
167
+ ### lib.rs
168
+
169
+ Don't forget to add this line
170
+
171
+ ```rust
172
+ .plugin(tauri_plugin_thermal_printer::init())
173
+ ```
174
+
175
+ ### Permission
176
+
177
+ Modify the file in /file/to/project/capabilities/default.json, and add:
178
+
179
+ ```json
180
+ {
181
+ "permissions": [
182
+ "core:default",
183
+ "thermal-printer:allow-list-thermal-printers",
184
+ "thermal-printer:allow-print-thermal-printer",
185
+ "thermal-printer:allow-test-thermal-printer"
186
+ ]
187
+ }
188
+ ```
189
+
190
+ ## Alternative Installation
191
+
192
+ ```bash
193
+ git clone https://github.com/luis3132/tauri-plugin-thermal-printer
194
+ cd tauri-plugin-thermal-printer
195
+ cargo build --release && bun i && bun run build
196
+ ```
197
+
198
+ on src-tauri project file
199
+
200
+ ```toml
201
+ [dependencies]
202
+ tauri-plugin-thermal-printer = { path = "../../tauri-plugin-thermal-printer" }
203
+ ```
204
+
205
+ on package.json
206
+
207
+ ```json
208
+ "dependencies": {
209
+ "tauri-plugin-thermal-printer-api": "file:../tauri-plugin-thermal-printer"
210
+ }
211
+ ```
212
+
213
+ ## Functions
214
+
215
+ ### List Printers
216
+
217
+ Get all printers available in the system. It just lists the configured printers...
218
+
219
+ #### Request:
220
+ ```typescript
221
+ import { list_thermal_printers } from "tauri-plugin-thermal-printer-api";
222
+
223
+ const response = await list_thermal_printers();
224
+ ```
225
+
226
+ #### Response
227
+ ```json
228
+ [
229
+ {
230
+ "name": "TM-T20II",
231
+ "interface_type": "USB",
232
+ "identifier": "usb://EPSON/TM-T20II",
233
+ "status": "IDLE"
234
+ },
235
+ {
236
+ "name": "Star TSP143III",
237
+ "interface_type": "NETWORK",
238
+ "identifier": "192.168.1.100:9100",
239
+ "status": "IDLE"
240
+ }
241
+ ]
242
+ ```
243
+
244
+ #### Response fields (array of PrinterInfo):
245
+ - `name` (string): Name of the printer
246
+ - `interface_type` (string): Interface type (e.g., "USB", "NETWORK")
247
+ - `identifier` (string): Unique identifier (e.g., USB path or IP:PORT)
248
+ - `status` (string): Current status (e.g., "IDLE", "BUSY")
249
+
250
+ ---
251
+
252
+ ### Test Printer
253
+
254
+ Send a print test to a specific printer to verify functionality.
255
+
256
+ #### Request:
257
+ ```typescript
258
+ import { test_thermal_printer, type TestPrintRequest } from "tauri-plugin-thermal-printer-api";
259
+
260
+ const response = await test_thermal_printer({
261
+ "printer_info": {
262
+ "printer": "TM-T20II",
263
+ "paper_size": "Mm80",
264
+ "options": {
265
+ "cut_paper": true,
266
+ "beep": true,
267
+ "open_cash_drawer": false
268
+ },
269
+ "sections": [] // it's not going to print anything
270
+ },
271
+ "include_text": true,
272
+ "include_text_styles": true,
273
+ "include_alignment": true,
274
+ "include_columns": true,
275
+ "include_separators": true,
276
+ "include_barcode": true,
277
+ "include_barcode_types": false,
278
+ "include_qr": true,
279
+ "include_image": false,
280
+ "image_base64": null,
281
+ "include_beep": true,
282
+ "test_cash_drawer": false,
283
+ "cut_paper": true,
284
+ "test_feed": true,
285
+ "test_all_fonts": false,
286
+ "test_invert": false,
287
+ "test_rotate": false
288
+ } as TestPrintRequest)
289
+ ```
290
+
291
+ #### Request parameters (TestPrintRequest):
292
+
293
+ | Parameter | Type | Required | Description |
294
+ |-----------|------|----------|-------------|
295
+ | `printer_info` | PrintJobRequest | ✅ Yes | Printer configuration (see Print Document) |
296
+ | `include_text` | boolean | ❌ No | Basic text test (default: `true`) |
297
+ | `include_text_styles` | boolean | ❌ No | Text styles test (bold, underline, inverted) (default: `true`) |
298
+ | `include_alignment` | boolean | ❌ No | Alignment test (left, center, right) (default: `true`) |
299
+ | `include_columns` | boolean | ❌ No | Column tables test (default: `true`) |
300
+ | `include_separators` | boolean | ❌ No | Separator lines test (default: `true`) |
301
+ | `include_barcode` | boolean | ❌ No | Barcode test (default: `true`) |
302
+ | `include_barcode_types` | boolean | ❌ No | Multiple barcode types test (default: `false`) |
303
+ | `include_qr` | boolean | ❌ No | QR code test (default: `true`) |
304
+ | `include_image` | boolean | ❌ No | Image printing test (default: `false`) |
305
+ | `image_base64` | string | ❌ No | Base64 image for testing (only if `include_image` is `true`) |
306
+ | `include_beep` | boolean | ❌ No | Acoustic signal test (default: `true`) |
307
+ | `test_cash_drawer` | boolean | ❌ No | Cash drawer opening test (default: `false`) |
308
+ | `cut_paper` | boolean | ❌ No | Cut paper at the end (default: `true`) |
309
+ | `test_feed` | boolean | ❌ No | Paper feed test (default: `true`) |
310
+ | `test_all_fonts` | boolean | ❌ No | Test all available fonts (default: `false`) |
311
+ | `test_invert` | boolean | ❌ No | Inverted text test (default: `false`) |
312
+ | `test_rotate` | boolean | ❌ No | Text rotation test (default: `false`) |
313
+
314
+ #### Response:
315
+ Returns `boolean`:
316
+ - `true`: Test completed successfully
317
+ - `false`: Test failed
318
+
319
+ ---
320
+
321
+ ### Print Document
322
+
323
+ Print a personalized document with the specified sections.
324
+
325
+ #### Request:
326
+ ```typescript
327
+ import { print_thermal_printer, type PrintJobRequest } from "tauri-plugin-thermal-printer-api";
328
+
329
+ const response = await print_thermal_printer({
330
+ "printer": "TM-T20II",
331
+ "paper_size": "Mm80",
332
+ "options": {
333
+ "cut_paper": true,
334
+ "beep": false,
335
+ "open_cash_drawer": false
336
+ },
337
+ "sections": [
338
+ {"Title": {"text": "My Business"}},
339
+ {"Subtitle": {"text": "Date: 01/01/2000"}},
340
+ {"Text": {"text": "Normal text", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
341
+ {"Feed": {"feed_type": "lines", "value": 3}},
342
+ {"Cut": {"mode": "full", "feed": 3}},
343
+ {"Beep": {"times": 1, "duration": 100}},
344
+ {"Drawer": {"pin": 2, "pulse_time": 100}},
345
+ {"Qr": {"data": "https://example.com", "size": 5, "error_correction": "M", "model": 2}},
346
+ {"Barcode": {"data": "123456789", "barcode_type": "CODE128", "width": 2, "height": 100, "text_position": "below"}},
347
+ {"Table": {"columns": 3, "column_widths": [10, 15, 10], "header": [{"text": "Col1"}, {"text": "Col2"}, {"text": "Col3"}], "body": [[{"text": "Data1"}, {"text": "Data2"}, {"text": "Data3"}]], "truncate": false}},
348
+ {"DataMatrix": {"data": "DataMatrix data", "size": 5}},
349
+ {"Pdf417": {"data": "PDF417 data", "columns": 2, "rows": 5, "width": 3, "height": 5, "error_correction": 2}},
350
+ {"Image": {"data": "{please introduce a base64 data image}", "max_width": 384, "align": "center", "dithering": true, "size": "normal"}},
351
+ {"Logo": {"key_code": 1, "mode": "normal"}},
352
+ {"Line": {"character": "="}}
353
+ ]
354
+ } as PrintJobRequest)
355
+ ```
356
+
357
+ #### Response:
358
+ Returns `boolean`:
359
+ - `true`: Print completed successfully
360
+ - `false`: Print failed
361
+
362
+ #### Main parameters (PrintJobRequest):
363
+
364
+ | Parameter | Type | Required | Description |
365
+ |-----------|------|----------|-------------|
366
+ | `printer` | string | ✅ Yes | Printer name |
367
+ | `paper_size` | string | ❌ No | Paper size: `"Mm58"` or `"Mm80"` (default: `"Mm80"`) |
368
+ | `options` | PrinterOptions | ❌ No | Configuration options |
369
+ | `options.cut_paper` | boolean | ❌ No | Cut paper after printing (default: `true`) |
370
+ | `options.beep` | boolean | ❌ No | Beep after printing (default: `false`) |
371
+ | `options.open_cash_drawer` | boolean | ❌ No | Open cash drawer after printing (default: `false`) |
372
+ | `sections` | array | ✅ Yes | Array of sections to print (see [Section Types](#section-types)) |
373
+
374
+ #### Section Types
375
+
376
+ Sections are defined as objects in the `sections` array. Each section is an enum variant with its data. Below are all supported section types:
377
+
378
+ ##### Title
379
+ Prints a title with forced double size and center alignment.
380
+
381
+ ```json
382
+ {
383
+ "Title": {
384
+ "text": "My Title",
385
+ "styles": {
386
+ "bold": false,
387
+ "underline": false,
388
+ "align": "center",
389
+ "italic": false,
390
+ "invert": false,
391
+ "font": "A",
392
+ "rotate": false,
393
+ "upside_down": false,
394
+ "size": "Double"
395
+ }
396
+ }
397
+ }
398
+ ```
399
+
400
+ Or simply:
401
+
402
+ ```json
403
+ {
404
+ "Title": {
405
+ "text": "My Title"
406
+ }
407
+ }
408
+ ```
409
+
410
+ - `text` (string, required): Title text
411
+ - `styles` (GlobalStyles, optional): Applied styles
412
+
413
+ ##### Subtitle
414
+ Prints a subtitle with forced bold and increased height.
415
+
416
+ ```json
417
+ {
418
+ "Subtitle": {
419
+ "text": "My Subtitle",
420
+ "styles": {
421
+ "bold": true,
422
+ "underline": false,
423
+ "align": "left",
424
+ "italic": false,
425
+ "invert": false,
426
+ "font": "A",
427
+ "rotate": false,
428
+ "upside_down": false,
429
+ "size": "height"
430
+ }
431
+ }
432
+ }
433
+ ```
434
+
435
+ Or simply:
436
+
437
+ ```json
438
+ {
439
+ "Subtitle": {
440
+ "text": "My Subtitle"
441
+ }
442
+ }
443
+ ```
444
+
445
+ - `text` (string, required): Subtitle text
446
+ - `styles` (GlobalStyles, optional): Applied styles
447
+
448
+ ##### Text
449
+ Prints simple text with optional styles.
450
+
451
+ ```json
452
+ {
453
+ "Text": {
454
+ "text": "Normal text",
455
+ "styles": {
456
+ "bold": false,
457
+ "underline": false,
458
+ "align": "left",
459
+ "italic": false,
460
+ "invert": false,
461
+ "font": "A",
462
+ "rotate": false,
463
+ "upside_down": false,
464
+ "size": "normal"
465
+ }
466
+ }
467
+ }
468
+ ```
469
+
470
+ Or
471
+
472
+ ```json
473
+ {
474
+ "Text": {
475
+ "text": "My Subtitle",
476
+ "styles": {
477
+ "bold": true,
478
+ "underline": true
479
+ }
480
+ }
481
+ }
482
+ ```
483
+
484
+ Or simple version
485
+
486
+ ```json
487
+ {
488
+ "Text": {
489
+ "text": "My Subtitle"
490
+ }
491
+ }
492
+ ```
493
+
494
+ You can pick the style that you need, it's not necessary to declared all of them.
495
+
496
+ - `text` (string, required): Text to print
497
+ - `styles` (GlobalStyles, optional): Applied styles (defaults to current global styles)
498
+
499
+ ##### Feed
500
+ Advances the paper by a specific number of lines.
501
+
502
+ ```json
503
+ {
504
+ "Feed": {
505
+ "feed_type": "lines",
506
+ "value": 3
507
+ }
508
+ }
509
+ ```
510
+
511
+ - `feed_type` (string, required): Feed type ("lines")
512
+ - `value` (number, required): Number of lines to advance
513
+
514
+ ##### Cut
515
+ Cuts the paper.
516
+
517
+ ```json
518
+ {
519
+ "Cut": {
520
+ "mode": "full",
521
+ "feed": 3
522
+ }
523
+ }
524
+ ```
525
+
526
+ - `mode` (string, required): Cut mode ("full", "partial")
527
+ - `feed` (number, required): Lines to advance before cutting
528
+
529
+ ##### Beep
530
+ Emits a beep.
531
+
532
+ ```json
533
+ {
534
+ "Beep": {
535
+ "times": 1,
536
+ "duration": 100
537
+ }
538
+ }
539
+ ```
540
+
541
+ - `times` (number, required): Number of beeps
542
+ - `duration` (number, required): Duration in milliseconds
543
+
544
+ ##### Drawer
545
+ Opens the cash drawer.
546
+
547
+ ```json
548
+ {
549
+ "Drawer": {
550
+ "pin": 2,
551
+ "pulse_time": 100
552
+ }
553
+ }
554
+ ```
555
+
556
+ - `pin` (number, required): Drawer pin (2 or 5)
557
+ - `pulse_time` (number, required): Pulse time in milliseconds
558
+
559
+ ##### Qr
560
+ Prints a QR code.
561
+
562
+ ```json
563
+ {
564
+ "Qr": {
565
+ "data": "https://example.com",
566
+ "size": 5,
567
+ "error_correction": "M",
568
+ "model": 2,
569
+ "align": "center"
570
+ }
571
+ }
572
+ ```
573
+
574
+ - `data` (string, required): QR data
575
+ - `size` (number, required): Module size (1-16)
576
+ - `error_correction` (string, required): Error correction level ("L", "M", "Q", "H")
577
+ - `model` (number, required): QR model (1 or 2)
578
+ - `align` (string, optional): Alignment ("left", "center", "right")
579
+
580
+ ##### Barcode
581
+ Prints a barcode.
582
+
583
+ ```json
584
+ {
585
+ "Barcode": {
586
+ "data": "123456789",
587
+ "barcode_type": "CODE128",
588
+ "width": 2,
589
+ "height": 100,
590
+ "text_position": "below"
591
+ }
592
+ }
593
+ ```
594
+
595
+ - `data` (string, required): Barcode data
596
+ - `barcode_type` (string, required): Type ("UPC-A", "UPC-E", "EAN13", "EAN8", "CODE39", "ITF", "CODABAR", "CODE93", "CODE128")
597
+ - `width` (number, required): Module width
598
+ - `height` (number, required): Height in dots
599
+ - `text_position` (string, required): Text position ("not_printed", "above", "below", "both")
600
+
601
+ ##### Table
602
+ Prints a table.
603
+
604
+ ```json
605
+ {
606
+ "Table": {
607
+ "columns": 3,
608
+ "column_widths": [10, 15, 10],
609
+ "header": [
610
+ {"text": "Col1"},
611
+ {"text": "Col2"},
612
+ {"text": "Col3"}
613
+ ],
614
+ "body": [
615
+ [
616
+ {"text": "Data1"},
617
+ {"text": "Data2"},
618
+ {"text": "Data3"}
619
+ ]
620
+ ],
621
+ "truncate": false
622
+ }
623
+ }
624
+ ```
625
+
626
+ Or simply:
627
+
628
+ ```json
629
+ {
630
+ "Table": {
631
+ "columns": 3,
632
+ "body": [
633
+ [
634
+ {"text": "Data1"},
635
+ {"text": "Data2"},
636
+ {"text": "Data3"}
637
+ ]
638
+ ]
639
+ }
640
+ }
641
+ ```
642
+
643
+ - `columns` (number, required): Number of columns
644
+ - `column_widths` (array, optional): Widths of each column. If not provided, columns will be evenly distributed across the paper width
645
+ - `header` (array, optional): Column headers (array of Text objects)
646
+ - `body` (array, required): Data rows (array of arrays of Text objects)
647
+ - `truncate` (boolean, optional): Truncate long text (default: false)
648
+
649
+ ##### DataMatrix
650
+ Prints a DataMatrix code.
651
+
652
+ ```json
653
+ {
654
+ "DataMatrix": {
655
+ "data": "DataMatrix data",
656
+ "size": 5
657
+ }
658
+ }
659
+ ```
660
+
661
+ - `data` (string, required): DataMatrix data
662
+ - `size` (number, required): Module size (1-16)
663
+
664
+ ##### Pdf417
665
+ Prints a PDF417 code.
666
+
667
+ ```json
668
+ {
669
+ "Pdf417": {
670
+ "data": "PDF417 data",
671
+ "columns": 2,
672
+ "rows": 5,
673
+ "width": 3,
674
+ "height": 5,
675
+ "error_correction": 2
676
+ }
677
+ }
678
+ ```
679
+
680
+ - `data` (string, required): PDF417 data
681
+ - `columns` (number, required): Number of data columns
682
+ - `rows` (number, required): Number of data rows
683
+ - `width` (number, required): Module width
684
+ - `height` (number, required): Module height
685
+ - `error_correction` (number, required): Error correction level (0-8)
686
+
687
+ ##### Image
688
+ Prints an image.
689
+
690
+ ```json
691
+ {
692
+ "Image": {
693
+ "data": "base64_encoded_image",
694
+ "max_width": 384,
695
+ "align": "center",
696
+ "dithering": true,
697
+ "size": "normal"
698
+ }
699
+ }
700
+ ```
701
+
702
+ - `data` (string, required): Base64 encoded image
703
+ - `max_width` (number, required): Maximum width in pixels
704
+ - `align` (string, required): Alignment ("left", "center", "right")
705
+ - `dithering` (boolean, required): Apply dithering
706
+ - `size` (string, required): Size ("normal", "double_width", "double_height", "quadruple")
707
+
708
+ ##### Logo
709
+ Prints a logo stored in the printer.
710
+
711
+ ```json
712
+ {
713
+ "Logo": {
714
+ "key_code": 1,
715
+ "mode": "normal"
716
+ }
717
+ }
718
+ ```
719
+
720
+ - `key_code` (number, required): Logo key code (1-255)
721
+ - `mode` (string, required): Print mode ("normal", "double_width", "double_height", "quadruple")
722
+
723
+ ##### Line
724
+ Prints a separator line.
725
+
726
+ ```json
727
+ {
728
+ "Line": {
729
+ "character": "="
730
+ }
731
+ }
732
+ ```
733
+
734
+ - `character` (string, required): Character for the line (e.g., "=", "-", "_")
735
+
736
+
737
+ ##### GlobalStyles
738
+ Changes the current global styles that will be applied to subsequent text sections. This allows you to set default styles without specifying them for each text element.
739
+
740
+ ```json
741
+ {
742
+ "GlobalStyles": {
743
+ "bold": false,
744
+ "underline": false,
745
+ "align": "left",
746
+ "italic": false,
747
+ "invert": false,
748
+ "font": "A",
749
+ "rotate": false,
750
+ "upside_down": false,
751
+ "size": "normal"
752
+ }
753
+ }
754
+ ```
755
+
756
+ - `bold` (boolean, optional): Bold text (default: `false`)
757
+ - `underline` (boolean, optional): Underlined text (default: `false`)
758
+ - `align` (string, optional): Alignment ("left", "center", "right") (default: `"left"`)
759
+ - `italic` (boolean, optional): Italic text (default: `false`)
760
+ - `invert` (boolean, optional): Inverted text (black background) (default: `false`)
761
+ - `font` (string, optional): Font ("A", "B", "C") (default: `"A"`)
762
+ - `rotate` (boolean, optional): Text rotated 90 degrees (default: `false`)
763
+ - `upside_down` (boolean, optional): Upside down text (default: `false`)
764
+ - `size` (string, optional): Size ("normal", "height", "width", "double") (default: `"normal"`)
765
+
766
+ ---
767
+
768
+ ## Examples
769
+
770
+ This section contains practical examples for different use cases. Each example demonstrates how to structure print jobs for various business scenarios.
771
+
772
+ > **NOTE:** Paper is automatically cut at the end of printing with a full cut. You don't need to add a `Cut` section manually unless you want a specific partial cut.
773
+
774
+ ### 🛒 Long Receipt (Supermarket - 80mm)
775
+
776
+ ```typescript
777
+ import { print_thermal_printer, type PrintJobRequest } from "tauri-plugin-thermal-printer-api";
778
+
779
+ const receipt: PrintJobRequest = {
780
+ "printer": "TM-T20II",
781
+ "paper_size": "Mm80",
782
+ "options": {
783
+ "cut_paper": true,
784
+ "beep": false,
785
+ "open_cash_drawer": false
786
+ },
787
+ "sections": [
788
+ {"Title": {"text": "SUPERMERCADO LA ECONOMÍA", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
789
+ {"Text": {"text": "Sucursal Centro", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
790
+ {"Text": {"text": "Av. Juárez #1234, Col. Centro", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
791
+ {"Text": {"text": "Tel: (555) 123-4567", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
792
+ {"Text": {"text": "RFC: SUPE850101ABC", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
793
+ {"Line": {"character": "="}},
794
+ {"Text": {"text": "TICKET DE COMPRA", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
795
+ {"Text": {"text": "Fecha: 14/10/2025 15:45:30", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
796
+ {"Text": {"text": "Ticket: #0012345", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
797
+ {"Text": {"text": "Cajero: María González", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
798
+ {"Text": {"text": "Caja: 03", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
799
+ {"Line": {"character": "="}},
800
+ {"Table": {
801
+ "columns": 4,
802
+ "column_widths": [5, 20, 11, 12],
803
+ "header": [
804
+ {"text": "CANT", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
805
+ {"text": "DESCRIPCIÓN", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
806
+ {"text": "P.U.", "styles": {"bold": true, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
807
+ {"text": "TOTAL", "styles": {"bold": true, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
808
+ ],
809
+ "body": [
810
+ [
811
+ {"text": "2", "styles": null},
812
+ {"text": "Leche Lala 1L", "styles": null},
813
+ {"text": "$22.50", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
814
+ {"text": "$45.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
815
+ ],
816
+ [
817
+ {"text": "1", "styles": null},
818
+ {"text": "Pan Bimbo Blanco", "styles": null},
819
+ {"text": "$38.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
820
+ {"text": "$38.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
821
+ ],
822
+ [
823
+ {"text": "3", "styles": null},
824
+ {"text": "Coca Cola 600ml", "styles": null},
825
+ {"text": "$16.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
826
+ {"text": "$48.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
827
+ ],
828
+ [
829
+ {"text": "1", "styles": null},
830
+ {"text": "Cereal Zucaritas", "styles": null},
831
+ {"text": "$75.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
832
+ {"text": "$75.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
833
+ ],
834
+ [
835
+ {"text": "1", "styles": null},
836
+ {"text": "Azúcar 1kg", "styles": null},
837
+ {"text": "$25.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
838
+ {"text": "$25.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
839
+ ]
840
+ ],
841
+ "truncate": false
842
+ }},
843
+ {"Line": {"character": "="}},
844
+ {"Table": {
845
+ "columns": 2,
846
+ "column_widths": [32, 16],
847
+ "header": [],
848
+ "body": [
849
+ [
850
+ {"text": "SUBTOTAL:", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
851
+ {"text": "$1,280.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
852
+ ],
853
+ [
854
+ {"text": "IVA (16%):", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
855
+ {"text": "$204.80", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
856
+ ]
857
+ ],
858
+ "truncate": false
859
+ }},
860
+ {"Line": {"character": "="}},
861
+ {"Text": {"text": "TOTAL: $1,484.80", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
862
+ {"Line": {"character": "="}},
863
+ {"Text": {"text": "Forma de Pago: EFECTIVO", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
864
+ {"Table": {
865
+ "columns": 2,
866
+ "column_widths": [32, 16],
867
+ "header": [],
868
+ "body": [
869
+ [
870
+ {"text": "Pago con:", "styles": null},
871
+ {"text": "$1,500.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
872
+ ],
873
+ [
874
+ {"text": "Cambio:", "styles": null},
875
+ {"text": "$15.20", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
876
+ ]
877
+ ],
878
+ "truncate": false
879
+ }},
880
+ {"Line": {"character": "-"}},
881
+ {"Text": {"text": "Artículos: 25", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
882
+ {"Text": {"text": "Ahorro total: $85.50", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
883
+ {"Line": {"character": "-"}},
884
+ {"Text": {"text": "¡GRACIAS POR SU COMPRA!", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
885
+ {"Text": {"text": "Vuelva pronto", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
886
+ {"Text": {"text": "www.supereconomia.com", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
887
+ {"Qr": {"data": "https://supereconomia.com/ticket/0012345", "size": 5, "error_correction": "M", "model": 2}},
888
+ {"Barcode": {"data": "0012345", "barcode_type": "CODE128", "width": 2, "height": 50, "text_position": "below"}},
889
+ {"Feed": {"feed_type": "lines", "value": 3}}
890
+ ]
891
+ };
892
+
893
+ await print_thermal_printer(receipt);
894
+ ```
895
+
896
+ ---
897
+
898
+ ### 🍕 Restaurant Ticket (80mm)
899
+
900
+ ```typescript
901
+ const restaurantTicket: PrintJobRequest = {
902
+ "printer": "TM-T20II",
903
+ "paper_size": "Mm80",
904
+ "options": {
905
+ "cut_paper": true,
906
+ "beep": false,
907
+ "open_cash_drawer": false
908
+ },
909
+ "sections": [
910
+ {"Title": {"text": "RESTAURANTE EL BUEN SABOR", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
911
+ {"Text": {"text": "Comida Mexicana", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
912
+ {"Text": {"text": "Tel: (555) 987-6543", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
913
+ {"Line": {"character": "="}},
914
+ {"Text": {"text": "ORDEN #145", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
915
+ {"Text": {"text": "Mesa: 12", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
916
+ {"Text": {"text": "Mesero: Carlos Ruiz", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
917
+ {"Text": {"text": "Fecha: 14/10/2025 14:30", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
918
+ {"Line": {"character": "="}},
919
+ {"Table": {
920
+ "columns": 3,
921
+ "column_widths": [5, 28, 15],
922
+ "header": [
923
+ {"text": "CANT", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
924
+ {"text": "PLATILLO", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
925
+ {"text": "PRECIO", "styles": {"bold": true, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
926
+ ],
927
+ "body": [
928
+ [
929
+ {"text": "2", "styles": null},
930
+ {"text": "Tacos al Pastor", "styles": null},
931
+ {"text": "$45.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
932
+ ],
933
+ [
934
+ {"text": "1", "styles": null},
935
+ {"text": "Enchiladas Verdes", "styles": null},
936
+ {"text": "$85.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
937
+ ],
938
+ [
939
+ {"text": "1", "styles": null},
940
+ {"text": "Pozole Grande", "styles": null},
941
+ {"text": "$95.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
942
+ ],
943
+ [
944
+ {"text": "3", "styles": null},
945
+ {"text": "Refresco 600ml", "styles": null},
946
+ {"text": "$36.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
947
+ ],
948
+ [
949
+ {"text": "1", "styles": null},
950
+ {"text": "Agua de Horchata", "styles": null},
951
+ {"text": "$25.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
952
+ ]
953
+ ],
954
+ "truncate": false
955
+ }},
956
+ {"Line": {"character": "="}},
957
+ {"Table": {
958
+ "columns": 2,
959
+ "column_widths": [32, 16],
960
+ "header": [],
961
+ "body": [
962
+ [
963
+ {"text": "SUBTOTAL:", "styles": null},
964
+ {"text": "$286.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
965
+ ],
966
+ [
967
+ {"text": "Propina Sugerida (10%):", "styles": null},
968
+ {"text": "$28.60", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
969
+ ]
970
+ ],
971
+ "truncate": false
972
+ }},
973
+ {"Line": {"character": "="}},
974
+ {"Text": {"text": "TOTAL: $314.60", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
975
+ {"Line": {"character": "="}},
976
+ {"Text": {"text": "¡Gracias por su visita!", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
977
+ {"Text": {"text": "Esperamos verlo pronto", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
978
+ {"Feed": {"feed_type": "lines", "value": 3}}
979
+ ]
980
+ };
981
+ ```
982
+
983
+ ---
984
+
985
+ ### 👨‍🍳 Kitchen Order (80mm)
986
+
987
+ ```typescript
988
+ const kitchenOrder: PrintJobRequest = {
989
+ "printer": "TM-T20II",
990
+ "paper_size": "Mm80",
991
+ "options": {
992
+ "cut_paper": true,
993
+ "beep": true,
994
+ "open_cash_drawer": false
995
+ },
996
+ "sections": [
997
+ {"Title": {"text": "*** COMANDA COCINA ***", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
998
+ {"Text": {"text": "Orden: #145", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
999
+ {"Text": {"text": "Mesa: 12", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1000
+ {"Text": {"text": "Hora: 14:30", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1001
+ {"Line": {"character": "="}},
1002
+ {"Text": {"text": "2x TACOS AL PASTOR", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1003
+ {"Text": {"text": " - Sin cebolla", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1004
+ {"Text": {"text": " - Extra cilantro", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1005
+ {"Line": {"character": "-"}},
1006
+ {"Text": {"text": "1x ENCHILADAS VERDES", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1007
+ {"Text": {"text": " - Término medio", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1008
+ {"Line": {"character": "-"}},
1009
+ {"Text": {"text": "1x POZOLE GRANDE", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1010
+ {"Text": {"text": " - Extra rábanos", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1011
+ {"Text": {"text": " - Sin orégano", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1012
+ {"Line": {"character": "="}},
1013
+ {"Text": {"text": "Mesero: Carlos", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1014
+ {"Text": {"text": "Notas: Cliente regular", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1015
+ {"Feed": {"feed_type": "lines", "value": 3}},
1016
+ {"Beep": {"times": 2, "duration": 100}}
1017
+ ]
1018
+ };
1019
+ ```
1020
+
1021
+ ---
1022
+
1023
+ ### 🏷️ Product Label (58mm)
1024
+
1025
+ ```typescript
1026
+ const productLabel: PrintJobRequest = {
1027
+ "printer": "TM-T20II",
1028
+ "paper_size": "Mm58",
1029
+ "options": {
1030
+ "cut_paper": true,
1031
+ "beep": false,
1032
+ "open_cash_drawer": false
1033
+ },
1034
+ "sections": [
1035
+ {"Title": {"text": "PRODUCTO", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
1036
+ {"Line": {"character": "-"}},
1037
+ {"Text": {"text": "Nombre: Laptop HP", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1038
+ {"Text": {"text": "Modelo: 15-dy2021la", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1039
+ {"Text": {"text": "UPC: 7501234567890", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1040
+ {"Line": {"character": "-"}},
1041
+ {"Text": {"text": "PRECIO: $12,999.00", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1042
+ {"Line": {"character": "-"}},
1043
+ {"Barcode": {"data": "7501234567890", "barcode_type": "EAN13", "width": 2, "height": 50, "text_position": "below"}},
1044
+ {"Feed": {"feed_type": "lines", "value": 2}}
1045
+ ]
1046
+ };
1047
+ ```
1048
+
1049
+ ---
1050
+
1051
+ ### 🎟️ Service Turn Ticket (58mm)
1052
+
1053
+ ```typescript
1054
+ const turnTicket: PrintJobRequest = {
1055
+ "printer": "TM-T20II",
1056
+ "paper_size": "Mm58",
1057
+ "options": {
1058
+ "cut_paper": true,
1059
+ "beep": true,
1060
+ "open_cash_drawer": false
1061
+ },
1062
+ "sections": [
1063
+ {"Title": {"text": "TICKET DE TURNO", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
1064
+ {"Line": {"character": "="}},
1065
+ {"Text": {"text": "A-123", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
1066
+ {"Line": {"character": "="}},
1067
+ {"Text": {"text": "Servicio: Cajas", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1068
+ {"Text": {"text": "Fecha: 14/10/2025", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1069
+ {"Text": {"text": "Hora: 15:45", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1070
+ {"Line": {"character": "-"}},
1071
+ {"Text": {"text": "En espera: 8 turnos", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1072
+ {"Text": {"text": "Tiempo aprox: 20 min", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1073
+ {"Line": {"character": "-"}},
1074
+ {"Qr": {"data": "A-123", "size": 4, "error_correction": "L", "model": 2}},
1075
+ {"Text": {"text": "Escanea para consultar", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1076
+ {"Feed": {"feed_type": "lines", "value": 2}},
1077
+ {"Beep": {"times": 1, "duration": 100}}
1078
+ ]
1079
+ };
1080
+ ```
1081
+
1082
+ ---
1083
+
1084
+ ### 🚗 Parking Ticket (80mm)
1085
+
1086
+ ```typescript
1087
+ const parkingTicket: PrintJobRequest = {
1088
+ "printer": "TM-T20II",
1089
+ "paper_size": "Mm80",
1090
+ "options": {
1091
+ "cut_paper": true,
1092
+ "beep": false,
1093
+ "open_cash_drawer": false
1094
+ },
1095
+ "sections": [
1096
+ {"Title": {"text": "ESTACIONAMIENTO", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
1097
+ {"Subtitle": {"text": "PLAZA COMERCIAL", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1098
+ {"Line": {"character": "="}},
1099
+ {"Text": {"text": "Ticket: E-5678", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1100
+ {"Text": {"text": "Entrada: 14/10/2025 10:15", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1101
+ {"Text": {"text": "Caseta: A-01", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1102
+ {"Line": {"character": "-"}},
1103
+ {"Text": {"text": "Vehículo: ABC-1234", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1104
+ {"Text": {"text": "Nivel: 2 - Zona B", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1105
+ {"Line": {"character": "="}},
1106
+ {"Text": {"text": "TARIFAS:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1107
+ {"Text": {"text": "Primera hora: $20.00", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1108
+ {"Text": {"text": "Hora adicional: $15.00", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1109
+ {"Text": {"text": "Máximo 24hrs: $180.00", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1110
+ {"Line": {"character": "-"}},
1111
+ {"Text": {"text": "CONSERVE SU TICKET", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1112
+ {"Text": {"text": "Para salida y pago", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1113
+ {"Barcode": {"data": "E5678", "barcode_type": "CODE128", "width": 2, "height": 60, "text_position": "below"}},
1114
+ {"Feed": {"feed_type": "lines", "value": 3}}
1115
+ ]
1116
+ };
1117
+ ```
1118
+
1119
+ ---
1120
+
1121
+ ### 🎫 Event Ticket (80mm)
1122
+
1123
+ ```typescript
1124
+ const eventTicket: PrintJobRequest = {
1125
+ "printer": "TM-T20II",
1126
+ "paper_size": "Mm80",
1127
+ "options": {
1128
+ "cut_paper": true,
1129
+ "beep": false,
1130
+ "open_cash_drawer": false
1131
+ },
1132
+ "sections": [
1133
+ {"Title": {"text": "CONCIERTO 2025", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
1134
+ {"Subtitle": {"text": "BANDA ROCK NACIONAL", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1135
+ {"Line": {"character": "="}},
1136
+ {"Text": {"text": "Boleto: #A-1234567", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1137
+ {"Text": {"text": "Fecha: 25/10/2025", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1138
+ {"Text": {"text": "Hora: 20:00 hrs", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1139
+ {"Text": {"text": "Lugar: Auditorio Nacional", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1140
+ {"Line": {"character": "-"}},
1141
+ {"Table": {
1142
+ "columns": 2,
1143
+ "column_widths": [24, 24],
1144
+ "header": [],
1145
+ "body": [
1146
+ [
1147
+ {"text": "Zona:", "styles": null},
1148
+ {"text": "Preferente A", "styles": null}
1149
+ ],
1150
+ [
1151
+ {"text": "Fila:", "styles": null},
1152
+ {"text": "12", "styles": null}
1153
+ ],
1154
+ [
1155
+ {"text": "Asiento:", "styles": null},
1156
+ {"text": "45", "styles": null}
1157
+ ]
1158
+ ],
1159
+ "truncate": false
1160
+ }},
1161
+ {"Line": {"character": "="}},
1162
+ {"Text": {"text": "PRECIO: $850.00", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1163
+ {"Line": {"character": "="}},
1164
+ {"Text": {"text": "Titular: Juan Pérez", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1165
+ {"Text": {"text": "ID: 1234567890", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1166
+ {"Line": {"character": "-"}},
1167
+ {"Text": {"text": "IMPORTANTE:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1168
+ {"Text": {"text": "- Presentar identificación", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1169
+ {"Text": {"text": "- Llegar 30 min antes", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1170
+ {"Text": {"text": "- No se permiten reembolsos", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1171
+ {"Qr": {"data": "TICKET-A1234567-CONCIERTO2025", "size": 6, "error_correction": "H", "model": 2}},
1172
+ {"Barcode": {"data": "A1234567", "barcode_type": "CODE128", "width": 2, "height": 60, "text_position": "below"}},
1173
+ {"Feed": {"feed_type": "lines", "value": 3}}
1174
+ ]
1175
+ };
1176
+ ```
1177
+
1178
+ ---
1179
+
1180
+ ### 💳 Payment Receipt (80mm)
1181
+
1182
+ ```typescript
1183
+ const paymentReceipt: PrintJobRequest = {
1184
+ "printer": "TM-T20II",
1185
+ "paper_size": "Mm80",
1186
+ "options": {
1187
+ "cut_paper": true,
1188
+ "beep": false,
1189
+ "open_cash_drawer": false
1190
+ },
1191
+ "sections": [
1192
+ {"Title": {"text": "COMPROBANTE DE PAGO", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
1193
+ {"Line": {"character": "="}},
1194
+ {"Text": {"text": "Banco Nacional", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1195
+ {"Text": {"text": "Sucursal Centro", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1196
+ {"Text": {"text": "Operación: 987654321", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1197
+ {"Text": {"text": "Fecha: 14/10/2025 16:23:45", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1198
+ {"Line": {"character": "="}},
1199
+ {"Text": {"text": "TRANSFERENCIA ELECTRÓNICA", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1200
+ {"Line": {"character": "-"}},
1201
+ {"Text": {"text": "De:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1202
+ {"Text": {"text": " Cuenta: ****5678", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1203
+ {"Text": {"text": " Nombre: Juan Pérez", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1204
+ {"Line": {"character": "-"}},
1205
+ {"Text": {"text": "Para:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1206
+ {"Text": {"text": " Cuenta: ****9012", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1207
+ {"Text": {"text": " Nombre: María López", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1208
+ {"Line": {"character": "="}},
1209
+ {"Text": {"text": "MONTO: $5,000.00 MXN", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1210
+ {"Line": {"character": "="}},
1211
+ {"Text": {"text": "Concepto:", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1212
+ {"Text": {"text": "Pago de renta mensual", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1213
+ {"Line": {"character": "-"}},
1214
+ {"Text": {"text": "Comisión: $0.00", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1215
+ {"Text": {"text": "IVA: $0.00", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1216
+ {"Line": {"character": "="}},
1217
+ {"Text": {"text": "TOTAL: $5,000.00", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1218
+ {"Line": {"character": "="}},
1219
+ {"Text": {"text": "Estado: EXITOSA", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1220
+ {"Text": {"text": "Referencia: 123456789012345", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1221
+ {"Text": {"text": "Folio fiscal: ABCD-1234-EFGH", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
1222
+ {"Feed": {"feed_type": "lines", "value": 3}}
1223
+ ]
1224
+ };
1225
+ ```
1226
+
1227
+ ---
1228
+
1229
+ ### 📋 Summary
1230
+
1231
+ #### Tables
1232
+ - **Columns**: Supports 2, 3, or 4 columns
1233
+ - **Column widths** are optional - distributed automatically if not specified
1234
+ - **Important**: Sum of widths should not exceed 48 characters (80mm) or 32 characters (58mm)
1235
+
1236
+ #### QR Codes
1237
+ - **Size**: 1-10 (recommended: 5-6)
1238
+ - **Error correction**: `"L"` (7%), `"M"` (15%), `"Q"` (25%), `"H"` (30%)
1239
+ - **Model**: 1 or 2 (recommended: 2)
1240
+
1241
+ #### Barcodes
1242
+ - **Types**: UPC-A, UPC-E, EAN13, EAN8, CODE39, ITF, CODABAR, CODE93, CODE128
1243
+ - **Height**: 30-100 dots (recommended: 50-60)
1244
+ - **Text position**: `"not_printed"`, `"above"`, `"below"`, `"both"`
1245
+
1246
+ #### Styles
1247
+ - Bold, underline, and invert styles are automatically reset after each section
1248
+ - No need to manually reset styles
1249
+
1250
+ #### Paper Cutting
1251
+ - **Automatic**: Paper is automatically cut at the end with a full cut
1252
+ - **Manual** (optional): Add a `Cut` section if you need a specific partial cut