tauri-plugin-thermal-printer
Tauri Plugin thermal-printer
BREAKING CHANGES: The 2.0.0 and newer versions removed the
PrinterOptionsinterface to simplify configuration. Theoptionsfield inPrintJobRequestnow directly accepts aCodePageobject. The shorthand options (cut_paper,beep, andopen_cash_drawer) have been removed. If you need these actions, explicitly append them as sections (e.g.,{"Cut": {"mode": "partial", "feed": 0}}) at the end of yoursectionsarray.
This plugin provides thermal printer functionality for Tauri applications, allowing you to print documents, test printers, and list available printers.
| Platform | Supported |
|---|---|
| Linux | |
| macOS | |
| Windows | |
| Android | ? |
| iOS | ? (Network + BLE) |
Table of Contents
How it Works
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.
Architecture
Frontend (JavaScript/TypeScript)
↓ (IPC Commands)
Tauri Core (Rust) ←— ESC/POS generation (shared across all platforms)
↓ (Platform-specific implementations)
├── Desktop: Operating System (Linux/macOS/Windows)
│ ↓ (Raw binary data)
│ Thermal Printer (ESC/POS protocol)
│
└── Android: Kotlin Plugin
↓ (Bluetooth SPP / RFCOMM)
Thermal Printer (ESC/POS protocol)
Core Components
1. Data Models (src/models/)
PrintJobRequest: Main structure defining a print jobPrintSections: Enum with all printable content types (Title, Text, Table, QR, etc.)GlobalStyles: Formatting styles (bold, alignment, size, etc.)
2. Tauri Commands (src/commands.rs)
Three main functions exposed to the frontend:
list_thermal_printers(): Lists available printersprint_thermal_printer(): Prints a documenttest_thermal_printer(): Runs functionality tests
3. Print Processing (src/process/process_print.rs)
Converts data structures into ESC/POS binary commands:
pub fn generate_document(&mut self, print_job: &PrintJobRequest) -> Result<Vec<u8>, String>
4. OS Integration (src/desktop_printers/ and android/)
- Linux/macOS: Uses CUPS system (
lpstat,lpcommands) - 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
- Android: Kotlin plugin with Bluetooth SPP and USB printer discovery and printing
Workflow
Printing a Document (Desktop):
- Frontend sends
PrintJobRequestwith sections and configuration - Tauri receives the command and processes it in Rust
ProcessPrintconverts each section into ESC/POS commands- Operating System sends binary data to the printer
- Thermal Printer interprets ESC/POS commands and prints
Printing a Document (Android):
- Frontend sends
PrintJobRequestwith sections and configuration - Rust generates ESC/POS binary data using the same
ProcessPrintpipeline and sends it Base64-encoded to the Kotlin plugin - Kotlin plugin decodes the payload and routes by the
identifierformat:- MAC address → Bluetooth SPP / RFCOMM (with reflection fallback for cheap POS printers)
VID:/PID:→ USB (bulkTransfer, runtime permission dialog)host:port→ Network (RAW/JetDirect TCP socket, port 9100)
- Thermal Printer interprets ESC/POS commands and prints
Print Structure Example:
{
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 6,
"encode": "WINDOWS_1252"
},
"sections": [
{"Title": {"text": "My Title"}},
{"Text": {"text": "Normal content"}},
{"Table": {"columns": 3, "body": [["A", "B", "C"]]}}
]
}
ESC/POS Protocol
The plugin translates all sections into ESC/POS (Escape Sequence for Point of Sale) commands, the de facto standard for thermal printers:
\x1B\x40- Initialize printer\x1B\x61\x01- Center text\x1B\x45\x01- Enable bold- etc.
Supported Content Types
- Text: Title, Subtitle, Text with optional styles
- Codes: QR, Barcode (incl. GS1-128 & GS1 DataBar), DataMatrix, PDF417, Aztec, 2D GS1 DataBar, MaxiCode, Composite
- Media: Images, Logos
- Control: Feed, Cut, Beep, Cash Drawer
- Tables: Configurable columns
- Lines: Horizontal separators
Platform Status
- Linux: Fully functional (CUPS)
- macOS: Fully functional (CUPS)
- Windows: Fully functional (WinAPI)
- Android: Bluetooth, USB and Network (WiFi) printer discovery and printing
- iOS: Network (WiFi) and BLE printing/discovery. Bluetooth Classic (SPP) and USB are not possible on iOS for third-party apps (Apple restriction — Classic requires MFi certification, USB host is unavailable).
Supported Connections
| Connection | Linux | macOS | Windows | Android | iOS |
|---|---|---|---|---|---|
| USB | |||||
| Network | |||||
| Bluetooth | (Classic SPP) | (BLE only) |
Android note: The plugin auto-routes by the format of the
printerfield inPrintJobRequest, so use the exactidentifierreturned bylist_thermal_printers:
Connection printer/identifierformatDiscovery Notes Bluetooth MAC address "AA:BB:CC:DD:EE:FF"Paired (bonded) devices Printer must be paired in Android Bluetooth settings first. Runtime permission requested automatically (Android 12+). USB "VID:<vendorId>/PID:<productId>"(decimal)Connected USB-host / OTG devices The system shows a one-time USB permission dialog on first print (unavoidable Android security step). Network "<host>:<port>"(e.g."192.168.1.100:9100")Automatic via NSD / mDNS ( _pdl-datastream._tcp,_printer._tcp,_ipp._tcp)Prints over a RAW/JetDirect TCP socket (port 9100). Phone and printer must be on the same network. No IP configuration or subnet scan required.
iOS note: Same auto-routing by
identifier. iOS cannot use Bluetooth Classic (SPP) or USB, so only two transports are available:
Connection printer/identifierformatDiscovery Notes Network "<host>:<port>"(e.g."192.168.1.100:9100")Automatic via Bonjour ( NetServiceBrowser, same service types as Android)RAW/JetDirect TCP socket (port 9100). BLE "BLE:<peripheral-uuid>"(iOS exposes a UUID, never a MAC)CoreBluetooth scan, printers matched by advertised name Writes ESC/POS to the first writable characteristic. Only works with BLE-capable printers. The host app (the Tauri app using this plugin) must add these keys to its
Info.plist, otherwise iOS blocks the features at runtime:<key>NSBluetoothAlwaysUsageDescription</key> <string>Connect to Bluetooth thermal printers</string> <key>NSLocalNetworkUsageDescription</key> <string>Discover network thermal printers</string> <key>NSBonjourServices</key> <array> <string>_pdl-datastream._tcp</string> <string>_printer._tcp</string> <string>_ipp._tcp</string> </array>
Installation
Rust
cargo add tauri-plugin-thermal-printer
Bun / NPM / PNPM
bun add tauri-plugin-thermal-printer
This library not only contains the connector to the backend. Also adds the types for the print structure...
lib.rs
Don't forget to add this line
.plugin(tauri_plugin_thermal_printer::init())
Permission
Modify the file in /file/to/project/capabilities/default.json, and add:
{
"permissions": [
"core:default",
"thermal-printer:allow-list-thermal-printers",
"thermal-printer:allow-print-thermal-printer",
"thermal-printer:allow-test-thermal-printer"
]
}
Alternative Installation
git clone https://github.com/luis3132/tauri-plugin-thermal-printer
cd tauri-plugin-thermal-printer
cargo build --release && bun i && bun run build
on src-tauri project file
[dependencies]
tauri-plugin-thermal-printer = { path = "../../tauri-plugin-thermal-printer" }
on package.json
"dependencies": {
"tauri-plugin-thermal-printer": "file:../tauri-plugin-thermal-printer"
}
Functions
List Printers
Get all printers available in the system. It just lists the configured printers...
Request:
import { list_thermal_printers } from "tauri-plugin-thermal-printer";
try {
const response = await list_thermal_printers();
} catch (error) {
console.log("List printers failed: " + error)
}
Response
[
{
"name": "TM-T20II",
"interface_type": "USB",
"identifier": "usb://EPSON/TM-T20II",
"status": "IDLE"
},
{
"name": "Star TSP143III",
"interface_type": "NETWORK",
"identifier": "192.168.1.100:9100",
"status": "IDLE"
}
]
Response fields (array of PrinterInfo):
name(string): Name of the printerinterface_type(string): Interface type (e.g., "USB", "NETWORK")identifier(string): Unique identifier (e.g., USB path or IP:PORT)status(string): Current status (e.g., "IDLE", "BUSY")
Test Printer
Send a print test to a specific printer to verify functionality.
Request:
import { ENCODE, test_thermal_printer, type TestPrintRequest } from "tauri-plugin-thermal-printer";
try { await test_thermal_printer({
"printer_info": {
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 6,
"encode": ENCODE.WINDOWS_1252,
"use_gbk": false
},
"sections": [] // it's not going to print anything
},
"include_text": true,
"include_text_styles": true,
"include_alignment": true,
"include_columns": true,
"include_separators": true,
"include_barcode": true,
"include_barcode_types": false,
"include_qr": true,
"include_image": false,
"image_base64": null,
"include_beep": true,
"test_cash_drawer": false,
"cut_paper": true,
"test_feed": true,
"test_all_fonts": false,
"test_invert": false,
"test_rotate": false
} as TestPrintRequest) } catch (error) { console.error("Test print failed:", error); }
Request parameters (TestPrintRequest):
| Parameter | Type | Required | Description |
|---|---|---|---|
printer_info |
PrintJobRequest | Yes | Printer configuration (see Print Document) |
include_text |
boolean | No | Basic text test (default: true) |
include_text_styles |
boolean | No | Text styles test (bold, underline, inverted) (default: true) |
include_alignment |
boolean | No | Alignment test (left, center, right) (default: true) |
include_columns |
boolean | No | Column tables test (default: true) |
include_separators |
boolean | No | Separator lines test (default: true) |
include_barcode |
boolean | No | Barcode test (default: true) |
include_barcode_types |
boolean | No | Multiple barcode types test (default: false) |
include_qr |
boolean | No | QR code test (default: true) |
include_image |
boolean | No | Image printing test (default: false) |
image_base64 |
string | No | Base64 image for testing (only if include_image is true) |
include_beep |
boolean | No | Acoustic signal test (default: true) |
test_cash_drawer |
boolean | No | Cash drawer opening test (default: false) |
cut_paper |
boolean | No | Cut paper at the end (default: true) |
test_feed |
boolean | No | Paper feed test (default: true) |
test_all_fonts |
boolean | No | Test all available fonts (default: false) |
test_invert |
boolean | No | Inverted text test (default: false) |
test_rotate |
boolean | No | Text rotation test (default: false) |
Response:
Returns Promise<void>. Resolves when the test print completes successfully. Throws a string with the error message if it fails. Use try/catch to handle errors — see Error Handling.
Print Document
Print a personalized document with the specified sections.
Request:
import { ENCODE, print_thermal_printer, type PrintJobRequest } from "tauri-plugin-thermal-printer";
try { await print_thermal_printer({
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 6,
"encode": ENCODE.WINDOWS_1252,
"use_gbk": false
},
"sections": [
{"Title": {"text": "My Business"}},
{"Subtitle": {"text": "Date: 01/01/2000"}},
{"Text": {"text": "Normal text", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Feed": {"feed_type": "lines", "value": 3}},
{"Cut": {"mode": "full", "feed": 3}},
{"Beep": {"times": 1, "duration": 100}},
{"Drawer": {"pin": 2, "pulse_time": 100}},
{"Qr": {"data": "https://example.com", "size": 5, "error_correction": "M", "model": 2}},
{"Barcode": {"data": "123456789012", "barcode_type": "CODE128", "width": 2, "height": 100, "text_position": "below"}},
{"Table": {"columns": 3, "column_widths": [16, 16, 16], "header": [{"text": "Col1"}, {"text": "Col2"}, {"text": "Col3"}], "body": [[{"text": "Data1"}, {"text": "Data2"}, {"text": "Data3"}]], "truncate": false}},
{"DataMatrix": {"data": "DataMatrix data", "size": 5}},
{"Pdf417": {"data": "PDF417 data", "columns": 2, "rows": 5, "width": 3, "height": 5, "error_correction": 2}},
{"Image": {"data": "{base64 image data}", "max_width": 384, "align": "center", "dithering": true, "size": "normal"}},
{"Logo": {"key_code": 1, "mode": "normal"}},
{"Line": {"character": "="}}
]
} as PrintJobRequest) } catch (error) { console.error("Print failed:", error); }
Response:
Returns Promise<void>. Resolves when printing completes successfully. Throws a string with the error message if the job fails (e.g., printer not found, invalid barcode data, QR data too long). Use try/catch to handle errors — see Error Handling.
Main parameters (PrintJobRequest):
| Parameter | Type | Required | Description |
|---|---|---|---|
printer |
string | Yes | Printer name |
paper_size |
PaperSize | No | Paper size (default: "Mm80") — see Paper Sizes |
options |
CodePage | Yes | Required ESC/POS page selection plus host-side encoding strategy — see CodePage |
sections |
array | Yes | Array of sections to print (see Section Types) |
Paper Sizes
| Value | Paper width | Chars/line | Typical use |
|---|---|---|---|
"Mm40" |
40mm | 21 | Handheld ticket printers |
"Mm44" |
44mm | 24 | Compact POS |
"Mm58" |
58mm | 32 | Small format (most common portable) |
"Mm72" |
72mm | 42 | Mid-range printers |
"Mm80" |
80mm | 48 | Standard large format (default) |
"Mm104" |
104mm | 62 | Wide format |
Paper Size Helpers (TypeScript)
The TypeScript package exports constants and helper functions with the same values used by the Rust backend.
import {
PAPER_SIZE_CHARS_PER_LINE,
PAPER_SIZE_PIXELS_WIDTH,
DEFAULT_PAPER_SIZE,
getPaperSizeCharsPerLine,
getPaperSizePixelsWidth,
type PaperSize,
} from "tauri-plugin-thermal-printer";
const size: PaperSize = "Mm58";
console.log(DEFAULT_PAPER_SIZE); // "Mm80"
console.log(PAPER_SIZE_CHARS_PER_LINE[size]); // 32
console.log(PAPER_SIZE_PIXELS_WIDTH[size]); // 384
// Equivalent helper functions:
console.log(getPaperSizeCharsPerLine(size)); // 32
console.log(getPaperSizePixelsWidth(size)); // 384
Values per paper size:
| PaperSize | Chars/line | Pixels width |
|---|---|---|
"Mm40" |
21 | 256 |
"Mm44" |
24 | 288 |
"Mm58" |
32 | 384 |
"Mm72" |
42 | 512 |
"Mm80" |
48 | 576 |
"Mm104" |
62 | 752 |
Error Handling
print_thermal_printer and test_thermal_printer now return Promise<void> and throw a descriptive string when something fails. Always wrap calls in try/catch:
import { print_thermal_printer, type PrintJobRequest } from "tauri-plugin-thermal-printer";
try {
await print_thermal_printer(job);
} catch (error) {
// `error` is a string describing what went wrong, e.g.:
// "Printer not specified"
// "Barcode data cannot be empty"
// "Barcode type 'EAN13' only accepts numeric digits"
// "QR data length 5000 exceeds maximum 4296 for error correction level 'M'"
// "Table row 2 has 2 cells but 3 columns declared"
// "column_widths sum (45) must equal paper chars_per_line (48)"
// "Image data cannot be empty"
console.error("Print failed:", error);
}
list_thermal_printers also throws on failure (e.g., CUPS not available):
try {
const printers = await list_thermal_printers();
} catch (error) {
console.error("Could not list printers:", error);
}
Section Types
Sections are defined as objects in the sections array. Each section is an enum variant with its data. Below are all supported section types.
Each section shows both the raw JSON shape and a Helper — a TypeScript factory function that builds the same section for you. All helpers are imported from the plugin's JS package:
import {
title, subtitle, text, line, feed, cut, beep, beep2, drawer, globalStyles, reset,
lineSpacing, charSpacing, position, tabStops, leftMargin, printAreaWidth,
qr, table, dataMatrix, pdf417, aztec, gs1Databar2d, maxicode, composite, image, logo,
// barcodes (charset-typed):
numericBarcode, numericBarcodeData, code39Barcode, code39BarcodeData,
codabarBarcode, codabarBarcodeData, asciiBarcode, gs1Barcode, gs1BarcodeData,
} from 'tauri-plugin-thermal-printer-api'
The import line is omitted from the per-section snippets below for brevity.
Title
Prints a title with forced double size and center alignment.
{
"Title": {
"text": "My Title",
"styles": {
"bold": false,
"underline": false,
"align": "center",
"italic": false,
"invert": false,
"font": "A",
"rotate": false,
"upside_down": false,
"size": "Double"
}
}
}
Or simply:
{
"Title": {
"text": "My Title"
}
}
text(string, required): Title textstyles(GlobalStyles, optional): Applied styles
Helper:
title('My Title')
title('My Title', { align: 'center' })
Subtitle
Prints a subtitle with forced bold and increased height.
{
"Subtitle": {
"text": "My Subtitle",
"styles": {
"bold": true,
"underline": false,
"align": "left",
"italic": false,
"invert": false,
"font": "A",
"rotate": false,
"upside_down": false,
"size": "height"
}
}
}
Or simply:
{
"Subtitle": {
"text": "My Subtitle"
}
}
text(string, required): Subtitle textstyles(GlobalStyles, optional): Applied styles
Helper:
subtitle('My Subtitle')
subtitle('My Subtitle', { bold: true, underline: true })
Text
Prints simple text with optional styles.
{
"Text": {
"text": "Normal text",
"styles": {
"bold": false,
"underline": false,
"align": "left",
"italic": false,
"invert": false,
"font": "A",
"rotate": false,
"upside_down": false,
"size": "normal"
}
}
}
Or
{
"Text": {
"text": "My Subtitle",
"styles": {
"bold": true,
"underline": true
}
}
}
Or simple version
{
"Text": {
"text": "My Subtitle"
}
}
You can pick the style that you need, it's not necessary to declared all of them.
text(string, required): Text to printstyles(GlobalStyles, optional): Applied styles (defaults to current global styles)
Helper:
text('Normal text')
text('Bold underlined', { bold: true, underline: true })
Feed
Advances the paper by a specific number of lines.
{
"Feed": {
"feed_type": "lines",
"value": 3
}
}
feed_type(string, required): Feed type:"lines"— advance N lines (ESC d n)"dots"— advance N dot rows (ESC J n)"line_feed"— send N raw LF characters
value(number, required): Amount to advance
Helper:
feed(3) // 3 lines
feed(24, 'dots') // 24 dot rows
Cut
Cuts the paper.
{
"Cut": {
"mode": "full",
"feed": 3
}
}
mode(string, required): Cut mode:"full"— full cut"partial"— partial cut (default fallback)"partial_alt"— partial cut (alternate)"partial_alt2"— full cut (alternate)
feed(number, required): Lines to advance before cutting
Helper:
cut() // partial cut, feed 4
cut('full', 3)
Beep
Emits a beep using the Epson command (ESC ( A).
{
"Beep": {
"times": 1,
"duration": 100
}
}
times(number, required): Number of beepsduration(number, required): Duration in milliseconds
Generic printers: many cheap/clone printers ignore
ESC ( A. If you don't hear a beep, useBeep2instead, which uses the widely-supportedESC Bcommand.
Helper:
beep(1, 100)
Beep2
Emits a beep using the generic buzzer command (ESC B n t). Use this for generic/clone printers that ignore Beep.
{
"Beep2": {
"times": 2,
"duration": 3
}
}
times(number, required): Number of beeps (1–9)duration(number, required): Duration per beep in ~100ms units (1–9)
Helper:
beep2(2, 3)
Drawer
Opens the cash drawer.
{
"Drawer": {
"pin": 2,
"pulse_time": 100
}
}
pin(number, required): Drawer pin (2 or 5)pulse_time(number, required): Pulse time in milliseconds
Helper:
drawer() // pin 2, 120ms pulse
drawer(5, 100)
Qr
Prints a QR code.
{
"Qr": {
"data": "https://example.com",
"size": 5,
"error_correction": "M",
"model": 2,
"align": "center"
}
}
data(string, required): QR data. Must not be empty. Maximum length depends on error correction level — the backend will throw if exceeded.size(number, required): Module size (1–16)error_correction(string, required):"L"(7089 chars max) |"M"(4296, default) |"Q"(2953) |"H"(1817)model(number, required): QR model (1or2)align(string, optional):"left"|"center"|"right"
Helper:
qr('https://example.com')
qr('https://example.com', { size: 5, error_correction: 'M', model: 2, align: 'center' })
Barcode
Prints a barcode.
{
"Barcode": {
"data": "123456789",
"barcode_type": "CODE128",
"width": 2,
"height": 100,
"text_position": "below",
"align": "center"
}
}
data(string, required): Barcode data. Must not be empty. Numeric-only types (UPC-A,UPC-E,EAN13,EAN8,ITF,GS1-DATABAR-OMNI,GS1-DATABAR-TRUNCATED,GS1-DATABAR-LIMITED) only accept digit characters — the backend will throw an error otherwise.barcode_type(string, required):"UPC-A"|"UPC-E"|"EAN13"|"EAN8"|"CODE39"|"ITF"|"CODABAR"|"CODE93"|"CODE128"|"GS1-128"|"GS1-DATABAR-OMNI"|"GS1-DATABAR-TRUNCATED"|"GS1-DATABAR-LIMITED"|"GS1-DATABAR-EXPANDED"width(number, required): Module width (1–6)height(number, required): Height in dots (must be > 0)text_position(string, required):"none"|"above"|"below"|"both"align(string, optional):"left"|"center"|"right"(default: current global alignment)
GS1 symbologies (
GS1-128and the fourGS1-DATABAR-*variants) require printer firmware support — many entry-level thermal printers do not implement them.GS1-128andGS1-DATABAR-EXPANDEDaccept GS1 AI data (application identifiers); theGS1-DATABAR-OMNI,GS1-DATABAR-TRUNCATEDandGS1-DATABAR-LIMITEDvariants take 13 numeric digits.
TypeScript — charset-typed factories (recommended): the JS bindings now group barcode
types by the character set each symbology accepts and force the payload type at compile time.
Build the data with the matching helper so wrong data is a compile error, not a runtime failure.
The Rust side keeps data as a string, so leading zeros are preserved.
import {
numericBarcode, numericBarcodeData,
code39Barcode, code39BarcodeData,
codabarBarcode, codabarBarcodeData,
asciiBarcode,
gs1Barcode, gs1BarcodeData,
} from 'tauri-plugin-thermal-printer-api'
numericBarcode(numericBarcodeData('0012345678905'), 'EAN13', { height: 100 }) // digits, zero-padding kept
code39Barcode(code39BarcodeData('ABC-123')) // digits, A-Z and - . $ / + %
codabarBarcode(codabarBarcodeData('A1234B')) // digits, - $ : / . + and A-D
asciiBarcode('Any ASCII', 'CODE128') // CODE93 / CODE128 — plain string
gs1Barcode(gs1BarcodeData('(01)00012345678905'), 'GS1-128') // GS1 AI format
// numericBarcode('123', 'EAN13') ❌ compile error: plain string not allowed for numeric types
The old untyped barcode(data, barcode_type, options) is @deprecated but still exported
for backwards compatibility (accepts any string).
Table
Prints a table.
{
"Table": {
"columns": 3,
"column_widths": [10, 15, 10],
"header": [
{"text": "Col1"},
{"text": "Col2"},
{"text": "Col3"}
],
"body": [
[
{"text": "Data1"},
{"text": "Data2"},
{"text": "Data3"}
]
],
"truncate": false
}
}
Or simply:
{
"Table": {
"columns": 3,
"body": [
[
{"text": "Data1"},
{"text": "Data2"},
{"text": "Data3"}
]
]
}
}
columns(number, required): Number of columnscolumn_widths(array, optional): Widths of each column in characters. When provided: length must equalcolumnsand the sum must equal the paper's chars/line (e.g., 48 for Mm80). If omitted, columns are distributed evenly.header(array, optional): Column headers — must have exactlycolumnselements if providedbody(array, required): Data rows — each row must have exactlycolumnscellstruncate(boolean, optional): Truncate long text instead of wrapping (default:false)
Helper: (cells are built with the text(...) helper)
table(3, [[text('Data1'), text('Data2'), text('Data3')]], {
header: [text('Col1'), text('Col2'), text('Col3')],
column_widths: [16, 16, 16],
})
DataMatrix
Prints a DataMatrix code.
{
"DataMatrix": {
"data": "DataMatrix data",
"size": 5
}
}
data(string, required): DataMatrix datasize(number, required): Module size (1-16)
Helper:
dataMatrix('DataMatrix data', 5)
Pdf417
Prints a PDF417 code.
{
"Pdf417": {
"data": "PDF417 data",
"columns": 2,
"rows": 5,
"width": 3,
"height": 5,
"error_correction": 2
}
}
data(string, required): PDF417 datacolumns(number, required): Number of data columnsrows(number, required): Number of data rowswidth(number, required): Module widthheight(number, required): Module heighterror_correction(number, required): Error correction level (0-8)
Helper:
pdf417('PDF417 data', { columns: 2, rows: 5, width: 3, height: 5, error_correction: 2 })
Advanced 2D codes. The four symbologies below (
Aztec,Gs1Databar2d,MaxiCode,Composite) require printer firmware support and are only implemented by advanced Epson models (e.g. TM-T88VI and higher). Most entry-level thermal printers ignore them. All four accept an optionalalign("left" | "center" | "right"), likeQr/Barcode.
Aztec
Prints an Aztec Code. Uses GS ( k with cn = 53.
{
"Aztec": {
"data": "Aztec data",
"mode": 0,
"layers": 0,
"size": 3,
"error_correction": 23,
"align": "center"
}
}
data(string, required): Aztec data. Must not be empty.mode(number, required):0= full range,1= compactlayers(number, required): Number of data layers,0= automatic (1–32)size(number, required): Module size (2–16)error_correction(number, required): Error correction as a percentage of capacity (5–95)align(string, optional):"left"|"center"|"right"
Helper:
aztec('Aztec data', { size: 3, error_correction: 23, align: 'center' })
Gs1Databar2d
Prints a 2D GS1 DataBar. Uses GS ( k with cn = 51.
{
"Gs1Databar2d": {
"data": "1234567890123",
"databar_type": "STACKED-OMNI",
"width": 2,
"align": "center"
}
}
data(string, required): GS1 DataBar data. Must not be empty.databar_type(string, required):"STACKED"|"STACKED-OMNI"|"EXPANDED-STACKED"width(number, required): Module width (2–8)align(string, optional):"left"|"center"|"right"
Helper:
gs1Databar2d('1234567890123', 'STACKED-OMNI', { width: 2, align: 'center' })
MaxiCode
Prints a MaxiCode (fixed physical size). Uses GS ( k with cn = 50.
{
"MaxiCode": {
"data": "MaxiCode data",
"mode": 4,
"align": "center"
}
}
data(string, required): MaxiCode data. Must not be empty.mode(number, required): Mode2–6(4is the general-purpose default)align(string, optional):"left"|"center"|"right"
Helper:
maxicode('MaxiCode data', { mode: 4, align: 'center' })
Composite
Prints a Composite Symbology (GS1 Composite CC-A/CC-B/CC-C). Uses GS ( k with cn = 52.
{
"Composite": {
"data": "Composite data",
"symbol_type": 48,
"width": 2,
"align": "center"
}
}
data(string, required): Composite data. Must not be empty.symbol_type(number, required): Themparameter selecting the 1D host + 2D component. Its exact value is printer/spec specific — check your device's ESC/POS reference.width(number, required): Module width (2–8)align(string, optional):"left"|"center"|"right"
Helper:
composite('Composite data', { symbol_type: 48, width: 2, align: 'center' })
Image
Prints an image.
{
"Image": {
"data": "base64_encoded_image",
"max_width": 384,
"align": "center",
"dithering": true,
"size": "normal"
}
}
data(string, required): Base64 encoded image. Must not be empty.max_width(number, required): Maximum width in pixels (0 or values larger than the paper width are clamped to the paper width automatically)align(string, required):"left"|"center"|"right"dithering(boolean, required): Apply Floyd-Steinberg dithering for better quality on monochrome printerssize(string, required):"normal"|"double_width"|"double_height"|"quadruple"
Helper:
image(base64Data, { max_width: 384, align: 'center', dithering: true, size: 'normal' })
Logo
Prints a logo stored in the printer.
{
"Logo": {
"key_code": 1,
"mode": "normal"
}
}
key_code(number, required): Logo key code (1-255)mode(string, required): Print mode ("normal", "double_width", "double_height", "quadruple")
Helper:
logo(1)
logo(1, 'double_width')
Line
Prints a separator line.
{
"Line": {
"character": "="
}
}
character(string, required): Character for the line (e.g., "=", "-", "_")
Helper:
line() // full-width row of '-'
line('=')
GlobalStyles
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.
{
"GlobalStyles": {
"bold": false,
"underline": false,
"align": "left",
"italic": false,
"invert": false,
"font": "A",
"rotate": false,
"upside_down": false,
"size": "normal",
"double_strike": false
}
}
bold(boolean, optional): Bold text (default:false)underline(boolean, optional): Underlined text (default:false)align(string, optional): Alignment ("left", "center", "right") (default:"left")italic(boolean, optional): Italic text (default:false)invert(boolean, optional): Inverted text (black background) (default:false)font(string, optional): Font ("A", "B", "C") (default:"A")rotate(boolean, optional): Text rotated 90 degrees (default:false)upside_down(boolean, optional): Upside down text (default:false)size(string, optional): Size ("normal", "height", "width", "double") (default:"normal")double_strike(boolean, optional): Double-strike / double-print (ESC G). Reinforces bold on generic printers that renderESC Eweakly (default:false)
Helper:
globalStyles({ bold: true, align: 'center' })
Reset
Pass reset: true in a GlobalStyles section to reset the printer (ESC @) and re-apply the code page. reset takes priority: all other style fields in the same section are ignored.
{ "GlobalStyles": { "reset": true } }
Helper:
reset() // shorthand for globalStyles({ reset: true })
LineSpacing
Sets the vertical line spacing (ESC 3 n). Omit value (or null) to reset to the printer default ~1/6" (ESC 2).
{ "LineSpacing": { "value": 20 } }
value(number, optional): Spacing in dots. Omit /null= default.
Helper:
lineSpacing(20)
lineSpacing() // reset to printer default
CharSpacing
Sets the right-side character spacing (ESC SP n).
{ "CharSpacing": { "value": 3 } }
value(number, required): Extra spacing per character, in dots (0–255).
Helper:
charSpacing(3)
Position
Sets the absolute horizontal print position for the next data (ESC $).
{ "Position": { "value": 200 } }
value(number, required): Distance from the left margin, in dots.
Helper:
position(200)
TabStops
Defines horizontal tab stops (ESC D ... NUL). Emit a \t inside your text to jump to the next stop.
{ "TabStops": { "positions": [10, 24] } }
positions(number[], required): Tab stop columns (in characters), ascending. Up to 32. Must not be empty.
Helper:
tabStops([10, 24])
LeftMargin
Sets the left margin in standard mode (GS L).
{ "LeftMargin": { "value": 60 } }
value(number, required): Left margin, in dots.
Helper:
leftMargin(60)
PrintAreaWidth
Sets the printable area width in standard mode (GS W).
{ "PrintAreaWidth": { "value": 512 } }
value(number, required): Printable area width, in dots.
Helper:
printAreaWidth(512)
Compatibility note: all of the above are classic single-letter ESC/POS commands with high support across generic/clone thermal printers.
TypeScript Constants & Helpers
The plugin exports typed constants and builder functions so you never have to type raw strings.
CodePage
Set the character encoding once in PrinterOptions.code_page and all text sections (Title, Subtitle, Text, Table) will use it automatically.
Each printer model assigns its own ESC t n values, so CodePage.code_page accepts the raw page number directly. CodePage.encode controls the host-side encoding used before bytes are sent to the printer. CodePage.use_gbk explicitly controls whether characters that the selected encode cannot represent should be retried with GBK before falling back to the original UTF-8 bytes.
import { ENCODE, type CodePage } from "tauri-plugin-thermal-printer";
const options = {
code_page: 6,
encode: ENCODE.WINDOWS_1252,
use_gbk: false,
};
CodePage fields:
| Field | Required | Description |
|---|---|---|
code_page |
Yes | Raw ESC t n value sent to the printer. |
encode |
No | Host-side encoding strategy. Defaults to ENCODE.ACCENT_REMOVER. |
use_gbk |
No | Retries GBK for characters that encode cannot represent before falling back to the original UTF-8 bytes. Defaults to false. |
ENCODE.ACCENT_REMOVER:
- Transliterates accented characters to ASCII before any optional GBK retry and final UTF-8 passthrough.
- Useful when the printer does not have a reliable legacy code page for your text.
- Examples:
á -> a,ß -> ss,€ -> EUR.
All other ENCODE.* values come directly from
encoding_rs statics.
Use them with the same uppercase names exposed by the package.
Examples:
ENCODE.WINDOWS_1252for Western European textENCODE.GBKfor GBK outputENCODE.SHIFT_JISfor Shift JIS output
Note:
options.code_pageis required. If the selectedencodecannot represent a character, the plugin retries GBK only whenuse_gbkistrue; otherwise it silently emits the original UTF-8 bytes for that character.
Style constants
Instead of typing raw strings you can import typed constant objects:
import {
TEXT_ALIGN,
TEXT_SIZE,
TEXT_FONT,
BARCODE_TYPE,
BARCODE_TEXT_POSITION,
QR_ERROR_CORRECTION,
IMAGE_MODE,
CUT_MODE,
} from "tauri-plugin-thermal-printer";
// Examples:
const styles = {
align: TEXT_ALIGN.CENTER, // "center"
size: TEXT_SIZE.DOUBLE, // "double"
font: TEXT_FONT.B, // "B"
bold: true,
};
const barcode = {
barcode_type: BARCODE_TYPE.EAN13, // "EAN13"
text_position: BARCODE_TEXT_POSITION.BELOW, // "below"
};
const qr = {
error_correction: QR_ERROR_CORRECTION.M, // "M"
};
| Export | Values |
|---|---|
TEXT_ALIGN |
LEFT CENTER RIGHT |
TEXT_SIZE |
NORMAL HEIGHT WIDTH DOUBLE |
TEXT_FONT |
A B C |
BARCODE_TYPE |
UPC_A UPC_E EAN13 EAN8 CODE39 ITF CODABAR CODE93 CODE128 GS1_128 GS1_DATABAR_OMNI GS1_DATABAR_TRUNCATED GS1_DATABAR_LIMITED GS1_DATABAR_EXPANDED |
BARCODE_TEXT_POSITION |
NONE ABOVE BELOW BOTH |
QR_ERROR_CORRECTION |
L M Q H |
IMAGE_MODE |
NORMAL DOUBLE_WIDTH DOUBLE_HEIGHT QUADRUPLE |
CUT_MODE |
FULL PARTIAL |
Section builder helpers
Short helper functions to build section types without enum wrapper boilerplate:
import {
title, subtitle, text, line, feed, cut, globalStyles,
beep, drawer, table, qr, barcode, dataMatrix, pdf417, image, logo,
TEXT_ALIGN, TEXT_SIZE, BARCODE_TYPE, QR_ERROR_CORRECTION,
} from "tauri-plugin-thermal-printer";
const sections = [
title("My Business"),
subtitle("Receipt #001"),
text("Thank you for your purchase!", { align: TEXT_ALIGN.CENTER }),
line("="),
qr("https://example.com/order/123", {
size: 6,
error_correction: QR_ERROR_CORRECTION.M,
}),
barcode("123456789012", BARCODE_TYPE.EAN13),
beep(),
text("Total: $50.00", { bold: true, size: TEXT_SIZE.DOUBLE }),
line("-"),
feed(3),
cut(),
];
| Helper | Description |
|---|---|
title(text, styles?) |
Creates a { Title: ... } section |
subtitle(text, styles?) |
Creates a { Subtitle: ... } section |
text(text, styles?) |
Creates a { Text: ... } section |
line(character?) |
Creates a { Line: ... } section (default "-") |
feed(value, type?) |
Creates a { Feed: ... } section (default "lines") |
cut(mode?, feedLines?) |
Creates a { Cut: ... } section (default "partial", 4 lines) |
globalStyles(styles) |
Creates a { GlobalStyles: ... } section |
reset() |
Creates a { GlobalStyles: { reset: true } } section — resets the printer and re-applies the code page |
beep(times?, duration?) |
Creates a { Beep: ... } section — Epson ESC ( A (default 1, 3) |
beep2(times?, duration?) |
Creates a { Beep2: ... } section — generic ESC B for clone printers (default 1, 3) |
lineSpacing(value?) |
Creates a { LineSpacing: ... } section — omit value to reset to default |
charSpacing(value) |
Creates a { CharSpacing: ... } section |
position(value) |
Creates a { Position: ... } section — absolute horizontal position in dots |
tabStops(positions) |
Creates a { TabStops: ... } section — emit \t in text to jump |
leftMargin(value) |
Creates a { LeftMargin: ... } section — margin in dots |
printAreaWidth(value) |
Creates a { PrintAreaWidth: ... } section — width in dots |
drawer(pin?, pulse_time?) |
Creates a { Drawer: ... } section (default 2, 120) |
table(columns, body, options?) |
Creates a { Table: ... } section (truncate default true) |
qr(data, options?) |
Creates a { Qr: ... } section (size=6, error_correction="M", model=2) |
barcode(data, barcode_type?, options?) |
Creates a { Barcode: ... } section (CODE128, width=3, height=80, text_position="below") |
dataMatrix(data, size?) |
Creates a { DataMatrix: ... } section (default size=6) |
pdf417(data, options?) |
Creates a { Pdf417: ... } section (columns=0, rows=0, width=2, height=3, error_correction=2) |
image(data, options?) |
Creates a { Image: ... } section (max_width=0, align="center", dithering=true, size="normal") |
logo(key_code, mode?) |
Creates a { Logo: ... } section (default mode="normal") |
Helper example (all builders)
import {
print_thermal_printer,
type PrintJobRequest,
title,
subtitle,
text,
line,
feed,
cut,
globalStyles,
beep,
drawer,
table,
qr,
barcode,
dataMatrix,
pdf417,
image,
logo,
ENCODE,
TEXT_ALIGN,
TEXT_SIZE,
BARCODE_TYPE,
BARCODE_TEXT_POSITION,
QR_ERROR_CORRECTION,
IMAGE_MODE,
} from "tauri-plugin-thermal-printer";
const job: PrintJobRequest = {
printer: "TM-T20II",
paper_size: "Mm80",
options: {
code_page: 0,
encode: ENCODE.ACCENT_REMOVER,
use_gbk: false,
},
sections: [
globalStyles({ align: TEXT_ALIGN.LEFT }),
title("DEMO STORE"),
subtitle("Receipt #A-1001"),
text("Date: 2026-03-30 14:22"),
line("="),
table(
3,
[
[text("1"), text("Americano"), text("$2.50", { align: TEXT_ALIGN.RIGHT })],
[text("2"), text("Croissant"), text("$7.00", { align: TEXT_ALIGN.RIGHT })],
],
{
column_widths: [6, 28, 14],
header: [
text("QTY", { bold: true }),
text("ITEM", { bold: true }),
text("TOTAL", { bold: true, align: TEXT_ALIGN.RIGHT }),
],
truncate: true,
},
),
line("-"),
text("Grand total: $9.50", { bold: true, size: TEXT_SIZE.DOUBLE, align: TEXT_ALIGN.RIGHT }),
qr("https://example.com/r/A-1001", {
size: 6,
error_correction: QR_ERROR_CORRECTION.M,
model: 2,
align: TEXT_ALIGN.CENTER,
}),
barcode("123456789012", BARCODE_TYPE.EAN13, {
width: 3,
height: 70,
text_position: BARCODE_TEXT_POSITION.BELOW,
align: TEXT_ALIGN.CENTER,
}),
dataMatrix("A-1001", 6),
pdf417("A-1001|TOTAL=9.50|PAID", {
columns: 0,
rows: 0,
width: 2,
height: 3,
error_correction: 2,
}),
image("<BASE64_IMAGE>", {
max_width: 0,
align: TEXT_ALIGN.CENTER,
dithering: true,
size: IMAGE_MODE.NORMAL,
}),
logo(1, IMAGE_MODE.NORMAL),
drawer(2, 120),
beep(1, 3),
feed(3),
cut(),
],
};
await print_thermal_printer(job);
Examples
This section contains practical examples for different use cases. Each example demonstrates how to structure print jobs for various business scenarios.
NOTE: With default options, a tail
Cutsection is appended automatically as{ "Cut": { "mode": "partial", "feed": 0 } }. Add your ownCutsection when you need an extra cut or different parameters.
Long Receipt (Supermarket - 80mm)
import { print_thermal_printer, type PrintJobRequest } from "tauri-plugin-thermal-printer";
const receipt: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"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"}}},
{"Text": {"text": "Sucursal Centro", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"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"}}},
{"Text": {"text": "RFC: SUPE850101ABC", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Line": {"character": "="}},
{"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"}}},
{"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"}}},
{"Text": {"text": "Ticket: #0012345", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Text": {"text": "Caja: 03", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Line": {"character": "="}},
{"Table": {
"columns": 4,
"column_widths": [5, 20, 11, 12],
"header": [
{"text": "CANT", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "DESCRIPCIÓN", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "P.U.", "styles": {"bold": true, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "TOTAL", "styles": {"bold": true, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
"body": [
[
{"text": "2", "styles": null},
{"text": "Leche Lala 1L", "styles": null},
{"text": "$22.50", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "$45.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "1", "styles": null},
{"text": "Pan Bimbo Blanco", "styles": null},
{"text": "$38.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "$38.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "3", "styles": null},
{"text": "Coca Cola 600ml", "styles": null},
{"text": "$16.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "$48.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "1", "styles": null},
{"text": "Cereal Zucaritas", "styles": null},
{"text": "$75.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "$75.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "1", "styles": null},
{"text": "Azúcar 1kg", "styles": null},
{"text": "$25.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "$25.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
]
],
"truncate": false
}},
{"Line": {"character": "="}},
{"Table": {
"columns": 2,
"column_widths": [32, 16],
"header": [],
"body": [
[
{"text": "SUBTOTAL:", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "$1,280.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "IVA (16%):", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "$204.80", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
]
],
"truncate": false
}},
{"Line": {"character": "="}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"Table": {
"columns": 2,
"column_widths": [32, 16],
"header": [],
"body": [
[
{"text": "Pago con:", "styles": null},
{"text": "$1,500.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "Cambio:", "styles": null},
{"text": "$15.20", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
]
],
"truncate": false
}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"Text": {"text": "Vuelva pronto", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Qr": {"data": "https://supereconomia.com/ticket/0012345", "size": 5, "error_correction": "M", "model": 2}},
{"Barcode": {"data": "0012345", "barcode_type": "CODE128", "width": 2, "height": 50, "text_position": "below"}},
{"Feed": {"feed_type": "lines", "value": 3}}
]
};
await print_thermal_printer(receipt);
Restaurant Ticket (80mm)
const restaurantTicket: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"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"}}},
{"Text": {"text": "Comida Mexicana", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Line": {"character": "="}},
{"Text": {"text": "ORDEN #145", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Text": {"text": "Mesa: 12", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"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"}}},
{"Line": {"character": "="}},
{"Table": {
"columns": 3,
"column_widths": [5, 28, 15],
"header": [
{"text": "CANT", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "PLATILLO", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}},
{"text": "PRECIO", "styles": {"bold": true, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
"body": [
[
{"text": "2", "styles": null},
{"text": "Tacos al Pastor", "styles": null},
{"text": "$45.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "1", "styles": null},
{"text": "Enchiladas Verdes", "styles": null},
{"text": "$85.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "1", "styles": null},
{"text": "Pozole Grande", "styles": null},
{"text": "$95.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "3", "styles": null},
{"text": "Refresco 600ml", "styles": null},
{"text": "$36.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "1", "styles": null},
{"text": "Agua de Horchata", "styles": null},
{"text": "$25.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
]
],
"truncate": false
}},
{"Line": {"character": "="}},
{"Table": {
"columns": 2,
"column_widths": [32, 16],
"header": [],
"body": [
[
{"text": "SUBTOTAL:", "styles": null},
{"text": "$286.00", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
],
[
{"text": "Propina Sugerida (10%):", "styles": null},
{"text": "$28.60", "styles": {"bold": false, "underline": false, "align": "right", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}
]
],
"truncate": false
}},
{"Line": {"character": "="}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"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"}}},
{"Feed": {"feed_type": "lines", "value": 3}}
]
};
Kitchen Order (80mm)
const kitchenOrder: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"Title": {"text": "*** COMANDA COCINA ***", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
{"Text": {"text": "Orden: #145", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Text": {"text": "Mesa: 12", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"Text": {"text": " - Sin cebolla", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Text": {"text": " - Extra cilantro", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"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"}}},
{"Line": {"character": "="}},
{"Text": {"text": "Mesero: Carlos", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Feed": {"feed_type": "lines", "value": 3}},
{"Beep": {"times": 2, "duration": 100}}
]
};
Product Label (58mm)
const productLabel: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm58",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"Title": {"text": "PRODUCTO", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"Text": {"text": "UPC: 7501234567890", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"Line": {"character": "-"}},
{"Barcode": {"data": "7501234567890", "barcode_type": "EAN13", "width": 2, "height": 50, "text_position": "below"}},
{"Feed": {"feed_type": "lines", "value": 2}}
]
};
Service Turn Ticket (58mm)
const turnTicket: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm58",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"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"}}},
{"Line": {"character": "="}},
{"Text": {"text": "A-123", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
{"Line": {"character": "="}},
{"Text": {"text": "Servicio: Cajas", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"Qr": {"data": "A-123", "size": 4, "error_correction": "L", "model": 2}},
{"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"}}},
{"Feed": {"feed_type": "lines", "value": 2}},
{"Beep": {"times": 1, "duration": 100}}
]
};
Parking Ticket (80mm)
const parkingTicket: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"Title": {"text": "ESTACIONAMIENTO", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
{"Subtitle": {"text": "PLAZA COMERCIAL", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Line": {"character": "="}},
{"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"}}},
{"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"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"Line": {"character": "="}},
{"Text": {"text": "TARIFAS:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"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"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"Barcode": {"data": "E5678", "barcode_type": "CODE128", "width": 2, "height": 60, "text_position": "below"}},
{"Feed": {"feed_type": "lines", "value": 3}}
]
};
Event Ticket (80mm)
const eventTicket: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"Title": {"text": "CONCIERTO 2025", "styles": {"bold": true, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "Double"}}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"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"}}},
{"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"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"Table": {
"columns": 2,
"column_widths": [24, 24],
"header": [],
"body": [
[
{"text": "Zona:", "styles": null},
{"text": "Preferente A", "styles": null}
],
[
{"text": "Fila:", "styles": null},
{"text": "12", "styles": null}
],
[
{"text": "Asiento:", "styles": null},
{"text": "45", "styles": null}
]
],
"truncate": false
}},
{"Line": {"character": "="}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"Text": {"text": "ID: 1234567890", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Line": {"character": "-"}},
{"Text": {"text": "IMPORTANTE:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"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"}}},
{"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"}}},
{"Qr": {"data": "TICKET-A1234567-CONCIERTO2025", "size": 6, "error_correction": "H", "model": 2}},
{"Barcode": {"data": "A1234567", "barcode_type": "CODE128", "width": 2, "height": 60, "text_position": "below"}},
{"Feed": {"feed_type": "lines", "value": 3}}
]
};
Payment Receipt (80mm)
const paymentReceipt: PrintJobRequest = {
"printer": "TM-T20II",
"paper_size": "Mm80",
"options": {
"code_page": 0,
"encode": ENCODE.ACCENT_REMOVER,
"use_gbk": false,
},
"sections": [
{"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"}}},
{"Line": {"character": "="}},
{"Text": {"text": "Banco Nacional", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Text": {"text": "Sucursal Centro", "styles": {"bold": false, "underline": false, "align": "center", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"Line": {"character": "-"}},
{"Text": {"text": "De:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Text": {"text": " Cuenta: ****5678", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"Text": {"text": "Para:", "styles": {"bold": true, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Text": {"text": " Cuenta: ****9012", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"Line": {"character": "="}},
{"Text": {"text": "Concepto:", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Line": {"character": "-"}},
{"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"}}},
{"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"}}},
{"Line": {"character": "="}},
{"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"}}},
{"Line": {"character": "="}},
{"Text": {"text": "Estado: EXITOSA", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"Text": {"text": "Referencia: 123456789012345", "styles": {"bold": false, "underline": false, "align": "left", "italic": false, "invert": false, "font": "A", "rotate": false, "upside_down": false, "size": "normal"}}},
{"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"}}},
{"Feed": {"feed_type": "lines", "value": 3}}
]
};
Summary
Tables
- Columns: Supports 2, 3, or 4 columns
- Column widths are optional - distributed automatically if not specified
- Important: Sum of widths should not exceed 48 characters (80mm) or 32 characters (58mm)
QR Codes
- Size: 1-10 (recommended: 5-6)
- Error correction:
"L"(7%),"M"(15%),"Q"(25%),"H"(30%) - Model: 1 or 2 (recommended: 2)
Barcodes
- Types: UPC-A, UPC-E, EAN13, EAN8, CODE39, ITF, CODABAR, CODE93, CODE128
- Height: 30-100 dots (recommended: 50-60)
- Text position:
"not_printed","above","below","both"
Styles
- Bold, underline, and invert styles are automatically reset after each section
- No need to manually reset styles
Paper Cutting
- Automatic:
options.cut_paper = trueappends a tailCutsection withmode: "partial"andfeed: 0 - Manual: Add a
Cutsection anywhere insectionsto issue explicit cut commands - Combined: Automatic and manual cuts are both emitted when both are present