portakal 0.2.0 → 0.4.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 CHANGED
@@ -4,7 +4,7 @@
4
4
  <br><br>
5
5
  <b style="font-size: 2em;">portakal</b>
6
6
  <br><br>
7
- Universal printer language SDK — TSC, ZPL, EPL, ESC/POS and more.
7
+ Universal printer language SDK — 9 languages, one API.
8
8
  <br>
9
9
  Text, barcodes, QR codes, images, shapes — anything you can print.
10
10
  <br>
@@ -14,6 +14,8 @@
14
14
  <a href="https://npmjs.com/package/portakal"><img src="https://img.shields.io/npm/dm/portakal?style=flat&colorA=18181B&colorB=F97316" alt="npm downloads"></a>
15
15
  <a href="https://bundlephobia.com/result?p=portakal"><img src="https://img.shields.io/bundlephobia/minzip/portakal?style=flat&colorA=18181B&colorB=F97316" alt="bundle size"></a>
16
16
  <a href="https://github.com/productdevbook/portakal/blob/main/LICENSE"><img src="https://img.shields.io/github/license/productdevbook/portakal?style=flat&colorA=18181B&colorB=F97316" alt="license"></a>
17
+ <br><br>
18
+ <a href="https://portakal.productdevbook.com">Playground</a> · <a href="https://github.com/productdevbook/portakal">GitHub</a> · <a href="https://npmjs.com/package/portakal">npm</a>
17
19
  </p>
18
20
 
19
21
  > [!NOTE]
@@ -28,37 +30,51 @@
28
30
  npm install portakal
29
31
  ```
30
32
 
31
- ### Product label (text + barcode + QR + shapes)
33
+ ### Product label
32
34
 
33
35
  ```ts
34
- import { label } from "portakal";
36
+ import { label } from "portakal/core";
37
+ import { tsc } from "portakal/lang/tsc";
35
38
 
36
- const cmd = label({ width: 40, height: 30, unit: "mm" })
39
+ const myLabel = label({ width: 40, height: 30, unit: "mm" })
37
40
  .text("ACME Corp", { x: 10, y: 10, size: 2 })
38
- .text("SKU: PRD-00123", { x: 10, y: 35, font: "2" })
39
- .barcode("123456789012", { type: "ean13", x: 10, y: 60, height: 50 })
40
- .qrcode("https://acme.com/prd/123", { x: 220, y: 60, ecc: "M", size: 5 })
41
- .line({ x1: 5, y1: 55, x2: 310, y2: 55, thickness: 1 })
42
- .box({ x: 5, y: 5, width: 310, height: 230, thickness: 2 })
43
- .toTSC();
41
+ .text("SKU: PRD-00123", { x: 10, y: 35 })
42
+ .line({ x1: 5, y1: 55, x2: 310, y2: 55 })
43
+ .box({ x: 5, y: 5, width: 310, height: 230, thickness: 2 });
44
+
45
+ const code = tsc.compile(myLabel); // TSC/TSPL2 commands
46
+ const svg = tsc.preview(myLabel); // SVG preview with TSC font metrics
44
47
  ```
45
48
 
46
- ### Shipping label (multiple text fields + barcode)
49
+ ### Same label any language
47
50
 
48
51
  ```ts
49
- const shipping = label({ width: 100, height: 150, unit: "mm" })
50
- .text("FROM: Warehouse A", { x: 10, y: 10 })
51
- .text("TO: John Doe", { x: 10, y: 30, size: 2 })
52
- .text("123 Main St, New York, NY 10001", { x: 10, y: 55 })
53
- .barcode("SSCC00012345678901234", { type: "code128", x: 10, y: 80, height: 80 })
54
- .qrcode("https://track.example.com/PKG123", { x: 300, y: 80, size: 8 })
55
- .line({ x1: 5, y1: 70, x2: 780, y2: 70, thickness: 2 })
56
- .toZPL();
52
+ import { label } from "portakal/core";
53
+ import { tsc } from "portakal/lang/tsc";
54
+ import { zpl } from "portakal/lang/zpl";
55
+ import { epl } from "portakal/lang/epl";
56
+ import { escpos } from "portakal/lang/escpos";
57
+
58
+ const myLabel = label({ width: 40, height: 30, unit: "mm" }).text("Hello World", {
59
+ x: 10,
60
+ y: 10,
61
+ size: 2,
62
+ });
63
+
64
+ tsc.compile(myLabel); // TSC/TSPL2 — TSC, Gprinter, Xprinter, iDPRT
65
+ zpl.compile(myLabel); // Zebra ZPL II — GK420, ZT410, ZD620
66
+ epl.compile(myLabel); // Eltron EPL2 — LP/TLP 2824, GX420, ZD220
67
+ escpos.compile(myLabel); // ESC/POS — Epson, Bixolon, Star, Citizen (Uint8Array)
57
68
  ```
58
69
 
59
- ### Receipt (ESC/POStext, barcode, QR)
70
+ Only the imported languages enter your bundle 100% tree-shakeable.
71
+
72
+ ### Receipt (ESC/POS)
60
73
 
61
74
  ```ts
75
+ import { label } from "portakal/core";
76
+ import { escpos } from "portakal/lang/escpos";
77
+
62
78
  const receipt = label({ width: 80, unit: "mm" })
63
79
  .text("MY STORE", { align: "center", bold: true, size: 2 })
64
80
  .text("123 Market St", { align: "center" })
@@ -66,66 +82,50 @@ const receipt = label({ width: 80, unit: "mm" })
66
82
  .text("Hamburger x2 $25.98")
67
83
  .text("Cola x1 $3.50")
68
84
  .text("================================")
69
- .text("TOTAL $29.48", { bold: true, size: 2 })
70
- .barcode("INV-20260402-001", { type: "code128", height: 60 })
71
- .qrcode("https://receipt.example.com/inv/001")
72
- .toESCPOS(); // Uint8Array (binary)
85
+ .text("TOTAL $29.48", { bold: true, size: 2 });
86
+
87
+ const bytes = escpos.compile(receipt); // Uint8Array
88
+ const svg = escpos.preview(receipt); // Receipt-style SVG
73
89
  ```
74
90
 
75
- ### Logo / image printing
91
+ ### Each module: compile + parse + preview + validate
76
92
 
77
93
  ```ts
78
- const cmd = label({ width: 40, height: 30, unit: "mm" })
79
- .image(myLogoBitmap, { x: 10, y: 10, width: 100 })
80
- .text("Company Name", { x: 120, y: 20, size: 2 })
81
- .toTSC();
82
- ```
94
+ import { tsc } from "portakal/lang/tsc";
83
95
 
84
- ### Same label → any printer language
96
+ // Compile: label → printer commands
97
+ tsc.compile(myLabel);
85
98
 
86
- ```ts
87
- const myLabel = label({ width: 40, height: 30, unit: "mm" })
88
- .text("Hello World", { x: 10, y: 10, size: 2 })
89
- .barcode("123456789", { type: "code128", x: 10, y: 50, height: 60 });
99
+ // Preview: label → SVG (per-language font metrics)
100
+ tsc.preview(myLabel);
101
+
102
+ // Parse: printer commands structured data
103
+ tsc.parse(tscCode); // { commands, elements, widthDots, ... }
90
104
 
91
- myLabel.toTSC(); // TSC/TSPL2 — TSC, Gprinter, Xprinter, iDPRT
92
- myLabel.toZPL(); // Zebra ZPL II — GK420, ZT410, ZD620
93
- myLabel.toEPL(); // Eltron EPL2 — LP/TLP 2824, GX420, ZD220
94
- myLabel.toESCPOS(); // ESC/POS — Epson, Bixolon, Star, Citizen
105
+ // Validate: check for errors
106
+ tsc.validate(tscCode); // { valid, errors, issues }
95
107
  ```
96
108
 
97
- ### Software-rendered barcode/QR (with etiket)
109
+ Available: `tsc`, `zpl`, `epl`, `cpcl`, `dpl`, `sbpl`, `escpos`, `starprnt`, `ipl`
98
110
 
99
- For pixel-perfect output, styled QR codes, or when the printer doesn't support a format natively:
111
+ ### Barcode/QR via etiket
100
112
 
101
- ```sh
102
- npm install portakal etiket
103
- ```
113
+ Use [`etiket`](https://github.com/productdevbook/etiket) for barcode/QR generation, then embed as image:
104
114
 
105
115
  ```ts
106
- import { label } from "portakal";
116
+ import { label } from "portakal/core";
117
+ import { tsc } from "portakal/lang/tsc";
107
118
  import { barcodePNG, qrcodePNG } from "etiket";
108
119
 
109
- // etiket renders barcode/QR as PNG portakal sends it as an image to the printer
110
- const cmd = label({ width: 40, height: 30, unit: "mm" })
120
+ const myLabel = label({ width: 40, height: 30, unit: "mm" })
111
121
  .text("Product Label", { x: 10, y: 5 })
112
122
  .image(barcodePNG("123456789", { type: "code128" }), { x: 10, y: 40, width: 200 })
113
- .image(qrcodePNG("https://example.com"), { x: 220, y: 40, width: 80 })
114
- .toZPL();
115
- ```
123
+ .image(qrcodePNG("https://example.com"), { x: 220, y: 40, width: 80 });
116
124
 
117
- ### When to use which?
125
+ const code = tsc.compile(myLabel);
126
+ ```
118
127
 
119
- | | Printer-native (`.barcode()` / `.qrcode()`) | Software-rendered (`.image()` + `etiket`) |
120
- | :------------------------------------ | :------------------------------------------ | :---------------------------------------- |
121
- | **Dependencies** | None | `etiket` (you install it) |
122
- | **Speed** | Fast (only sends command text) | Slower (sends pixel data) |
123
- | **Data size** | Small (~50 bytes) | Larger (bitmap data) |
124
- | **Consistency** | Varies by printer model | Identical on every printer |
125
- | **Format support** | Depends on printer (10-20 types) | 40+ barcode types, styled QR |
126
- | **Styled QR** (dots, gradients, logo) | Not possible | Full support via etiket |
127
- | **Works on cheap printers** | May not support QR/PDF417 | Always works (it's just an image) |
128
- | **Best for** | Simple labels, fast printing | Pixel-perfect, guaranteed output |
128
+ | **Best for** | Simple labels, fast printing | Pixel-perfect, guaranteed output |
129
129
 
130
130
  ## API
131
131
 
@@ -163,56 +163,6 @@ builder.text("Hello", {
163
163
  });
164
164
  ```
165
165
 
166
- ### `.barcode(data, options)`
167
-
168
- Printer-native barcode (uses the printer's built-in encoder):
169
-
170
- ```ts
171
- builder.barcode("123456789", {
172
- type: "code128", // Symbology (see table below)
173
- x: 10,
174
- y: 50, // Position
175
- height: 80, // Bar height in dots
176
- narrowWidth: 2, // Narrow bar width
177
- wideWidth: 4, // Wide bar width
178
- readable: true, // Show human-readable text
179
- readablePosition: "below", // "none" | "above" | "below" | "both"
180
- rotation: 0, // 0 | 90 | 180 | 270
181
- });
182
- ```
183
-
184
- **Supported barcode types:**
185
-
186
- | Type | Description |
187
- | :----------------------------------- | :--------------------- |
188
- | `code128` | Code 128 (auto subset) |
189
- | `code128a` / `code128b` / `code128c` | Code 128 subsets |
190
- | `code39` | Code 39 |
191
- | `code93` | Code 93 |
192
- | `ean13` / `ean8` | EAN-13 / EAN-8 |
193
- | `upca` / `upce` | UPC-A / UPC-E |
194
- | `itf` / `itf14` | Interleaved 2 of 5 |
195
- | `codabar` | Codabar |
196
- | `msi` | MSI Plessey |
197
- | `plessey` | Plessey |
198
- | `code11` | Code 11 |
199
- | `postnet` / `planet` | USPS Postnet / Planet |
200
- | `gs1_128` | GS1-128 |
201
- | `gs1_databar` | GS1 DataBar |
202
-
203
- ### `.qrcode(data, options?)`
204
-
205
- ```ts
206
- builder.qrcode("https://example.com", {
207
- x: 10,
208
- y: 100, // Position
209
- ecc: "M", // "L" | "M" | "Q" | "H"
210
- size: 6, // Module size 1-10
211
- model: 2, // QR model 1 | 2
212
- rotation: 0, // 0 | 90 | 180 | 270
213
- });
214
- ```
215
-
216
166
  ### `.image(bitmap, options?)`
217
167
 
218
168
  ```ts
@@ -253,20 +203,16 @@ builder.raw("^FO10,10^FDCustom^FS"); // ZPL
253
203
  builder.raw(new Uint8Array([0x1b, 0x70, 0x00, 0x32, 0x32])); // ESC/POS cash drawer
254
204
  ```
255
205
 
256
- ### Output Methods
257
-
258
- | Method | Output | Target |
259
- | :-------------- | :----------- | :------------------------------ |
260
- | `.toTSC()` | `string` | TSC/TSPL2 label printers |
261
- | `.toZPL()` | `string` | Zebra ZPL II printers |
262
- | `.toEPL()` | `string` | Eltron EPL2 printers |
263
- | `.toCPCL()` | `string` | Zebra mobile printers |
264
- | `.toDPL()` | `string` | Honeywell/Datamax printers |
265
- | `.toSBPL()` | `string` | SATO printers |
266
- | `.toESCPOS()` | `Uint8Array` | ESC/POS receipt printers |
267
- | `.toStarPRNT()` | `Uint8Array` | Star Micronics printers |
268
- | `.toIPL()` | `string` | Intermec/Honeywell printers |
269
- | `.toPreview()` | `string` | SVG preview (no printer needed) |
206
+ ### Language Module Methods
207
+
208
+ Each language module (`tsc`, `zpl`, `epl`, `cpcl`, `dpl`, `sbpl`, `escpos`, `starprnt`, `ipl`) has:
209
+
210
+ | Method | Output | Description |
211
+ | :-------------------- | :----------------------- | :--------------------------------------- |
212
+ | `lang.compile(label)` | `string` or `Uint8Array` | Compile to printer commands |
213
+ | `lang.preview(label)` | `string` | SVG preview with language-specific fonts |
214
+ | `lang.parse(code)` | `object` | Parse printer commands → structured data |
215
+ | `lang.validate(code)` | `object` | Validate commands for errors/warnings |
270
216
 
271
217
  ### Image Processing
272
218
 
@@ -279,7 +225,7 @@ const bitmap = imageToMonochrome(rgbaPixels, width, height, {
279
225
  dither: "floyd-steinberg", // "threshold" | "floyd-steinberg" | "atkinson" | "ordered"
280
226
  });
281
227
 
282
- label({ width: 40, height: 30 }).image(bitmap, { x: 10, y: 10 }).toTSC();
228
+ tsc.compile(label({ width: 40, height: 30 }).image(bitmap, { x: 10, y: 10 }));
283
229
  ```
284
230
 
285
231
  ### Receipt Layout
@@ -310,6 +256,60 @@ formatTable(
310
256
  );
311
257
  ```
312
258
 
259
+ ### Cross-Compiler
260
+
261
+ Convert between any printer languages — world's first thermal printer translator:
262
+
263
+ ```ts
264
+ import { convert } from "portakal";
265
+
266
+ // TSC → ZPL
267
+ const { output } = convert(tscCode, "tsc", "zpl");
268
+
269
+ // ZPL → ESC/POS
270
+ const { output } = convert(zplCode, "zpl", "escpos");
271
+
272
+ // EPL → CPCL
273
+ const { output } = convert(eplCode, "epl", "cpcl");
274
+ ```
275
+
276
+ 7 source × 9 target = **63 conversion paths**.
277
+
278
+ ### Validation
279
+
280
+ Check printer commands for errors before sending to printer:
281
+
282
+ ```ts
283
+ import { validate } from "portakal";
284
+
285
+ const result = validate(code, "tsc");
286
+ // { valid: false, errors: 1, warnings: 2, issues: [
287
+ // { level: "error", message: "CLS must appear before label elements" },
288
+ // { level: "warning", message: "No PRINT command found" },
289
+ // ]}
290
+ ```
291
+
292
+ TSC validation: SIZE order, CLS before elements, PRINT required, DENSITY 0-15, SPEED 1-18.
293
+ ZPL validation: ^XA/^XZ required, ^FD without ^FO, ^PW range.
294
+
295
+ ### Printer Profiles
296
+
297
+ Auto-configure DPI, paper width, and capabilities based on printer model:
298
+
299
+ ```ts
300
+ import { label, getProfile, findByVendorId } from "portakal";
301
+
302
+ // Auto-DPI from profile
303
+ label({ width: 40, height: 30, printer: "tsc-te310" }); // 300 DPI
304
+ label({ width: 80, printer: "epson-tm-t88vi" }); // 203 DPI
305
+
306
+ // Lookup profiles
307
+ getProfile("zebra-zd420"); // { name, dpi, paperWidth, ... }
308
+ findByVendorId(0x04b8); // All Epson printers
309
+ ```
310
+
311
+ 20 built-in profiles: Epson, Star, Bixolon, Citizen, TSC, Zebra, SATO, Honeywell, Generic.
312
+
313
313
  ## Supported Printer Languages
314
314
 
315
315
  | Language | Printers | Status |
@@ -331,24 +331,23 @@ formatTable(
331
331
  portakal generates commands only — it does **not** handle printer connections. Send the output over any transport you choose:
332
332
 
333
333
  ```ts
334
- import { label } from "portakal";
334
+ import { label } from "portakal/core";
335
+ import { tsc } from "portakal/lang/tsc";
336
+ import { escpos } from "portakal/lang/escpos";
335
337
  import net from "node:net";
336
338
 
337
- const commands = label({ width: 40, height: 30 }).text("Hello", { x: 10, y: 10 }).toTSC();
339
+ const myLabel = label({ width: 40, height: 30 }).text("Hello", { x: 10, y: 10 });
340
+ const commands = tsc.compile(myLabel);
338
341
 
339
342
  // TCP (port 9100)
340
343
  const socket = net.createConnection({ host: "192.168.1.100", port: 9100 });
341
344
  socket.write(commands);
342
345
  socket.end();
343
346
 
344
- // USB (via serialport)
345
- import { SerialPort } from "serialport";
346
- const port = new SerialPort({ path: "/dev/usb/lp0", baudRate: 9600 });
347
- port.write(commands);
348
-
349
347
  // ESC/POS (binary) over WebUSB
350
- const escpos = label({ width: 80 }).text("Receipt").toESCPOS();
351
- await usbDevice.transferOut(endpointNumber, escpos);
348
+ const receipt = label({ width: 80 }).text("Receipt");
349
+ const bytes = escpos.compile(receipt);
350
+ await usbDevice.transferOut(endpointNumber, bytes);
352
351
  ```
353
352
 
354
353
  ## Comparison
@@ -366,6 +365,10 @@ await usbDevice.transferOut(endpointNumber, escpos);
366
365
  | Image dithering | :white_check_mark: | :x: | :x: | :x: |
367
366
  | Receipt layout engine | :white_check_mark: | Partial | :x: | :x: |
368
367
  | SVG preview | :white_check_mark: | :x: | :x: | :x: |
368
+ | Command parser (reverse) | :white_check_mark: 9 parsers | :x: | :x: | :x: |
369
+ | Cross-compiler (translate) | :white_check_mark: 63 paths | :x: | :x: | :x: |
370
+ | Command validation | :white_check_mark: | :x: | :x: | :x: |
371
+ | Printer profiles | :white_check_mark: 20 | :x: | :x: | :x: |
369
372
  | Works in browser | :white_check_mark: | :x: | :x: | :white_check_mark: |
370
373
  | No native modules (no gyp) | :white_check_mark: | :x: | :x: | :white_check_mark: |
371
374
  | Pure ESM | :white_check_mark: | :x: (CJS) | :x: (CJS) | :x: (CJS) |
@@ -376,30 +379,39 @@ await usbDevice.transferOut(endpointNumber, escpos);
376
379
 
377
380
  - Zero dependencies — pure computation, no native modules, no node-gyp
378
381
  - **9 printer languages** — TSC, ZPL, EPL, CPCL, DPL, SBPL, ESC/POS, Star PRNT, IPL
382
+ - **Tree-shakeable** — sub-path exports for every module (`portakal/tsc`, `portakal/image`, etc.)
379
383
  - Pure ESM, edge-runtime compatible (Cloudflare Workers, Deno, Bun)
380
384
  - TypeScript-first with strict types (tsgo)
381
385
  - Transport-agnostic — generates commands, you handle the connection
382
386
  - Fluent builder API — one label definition compiles to any language
383
387
  - **Image processing** — RGBA → monochrome with 4 dithering algorithms (Floyd-Steinberg, Atkinson, ordered, threshold)
384
388
  - **Receipt layout engine** — same-line left+right alignment, tables, word-wrap, separators
385
- - **SVG preview** — `.toPreview()` renders labels without a physical printer
389
+ - **SVG preview** — `lang.preview(label)` renders labels without a physical printer
390
+ - **9 parsers** — reverse-parse printer commands back to structured data (TSC, ZPL, EPL, CPCL, ESC/POS, DPL, SBPL, Star PRNT, IPL)
386
391
  - Drawing primitives — box, line, circle, diagonal
387
392
  - Raw command passthrough for advanced/unsupported features
388
393
  - Optional [`etiket`](https://github.com/productdevbook/etiket) integration for barcode/QR images (40+ formats)
389
394
  - Works in browser, Node.js, Deno, Bun, Electron
390
395
  - **UTF-8 encoding engine** — auto code page selection (CP437, CP858, CP1252, CP866, CP857)
391
- - 184 tests across 15 test files
396
+ - **Cross-compiler** convert between any languages (63 paths: TSC↔ZPL↔EPL↔CPCL↔DPL↔SBPL↔IPL↔ESC/POS↔Star)
397
+ - **Real validation** — parameter ranges, command order, structure checks
398
+ - **20 printer profiles** — auto-DPI, auto-width by model (Epson, Star, Zebra, TSC, SATO, etc.)
399
+ - **Language modules** — each language is a standalone module (compile + parse + preview + validate)
400
+ - **Per-language SVG preview** — TSC fonts differ from ZPL fonts, ESC/POS renders receipt-style
401
+ - 447 tests across 28 test files
392
402
 
393
403
  ## Contributing
394
404
 
395
405
  Contributions are welcome! Here are areas where help is especially appreciated:
396
406
 
397
- - **IPL, Fingerprint, Argox PPLA/PPLB** compiler implementations
398
- - UTF-8 encoding engine (auto code page selection)
399
- - Arabic/Hebrew RTL support (bidi + shaping)
400
- - Printer capability profiles (auto-detect features per model)
401
- - Transport layer implementations (WebUSB, WebSerial, Web Bluetooth)
402
- - Star TSP100 raster-only mode
407
+ - **Arabic/Hebrew RTL** support (bidi algorithm + Arabic shaping)
408
+ - **GS1/UDI label standards** (SSCC, GTIN, FMD, DSCSA templates)
409
+ - **Star TSP100** raster-only text rendering
410
+ - **CJK encoding** (GB18030, Shift_JIS, Big5, EUC-KR)
411
+ - **Fingerprint** (Honeywell BASIC-like) compiler
412
+ - **WebUSB/WebSerial/Web Bluetooth** transport adapters
413
+ - Additional printer profiles
414
+ - Parser validation rules for more languages
403
415
 
404
416
  ```bash
405
417
  pnpm install # Install dependencies
@@ -0,0 +1,202 @@
1
+ //#region src/types.d.ts
2
+ /** Unit of measurement for label dimensions */
3
+ type Unit = "mm" | "inch" | "dot";
4
+ /** Print orientation / rotation */
5
+ type Rotation = 0 | 90 | 180 | 270;
6
+ /** Text alignment */
7
+ type Alignment = "left" | "center" | "right";
8
+ /** Dithering algorithm for image processing */
9
+ type DitherAlgorithm = "threshold" | "floyd-steinberg" | "atkinson" | "ordered";
10
+ /** Label configuration */
11
+ interface LabelConfig {
12
+ /** Printer profile ID (e.g., "epson-tm-t88vi", "zebra-zd420"). Overrides width, dpi, etc. */
13
+ printer?: string;
14
+ /** Label width */
15
+ width: number;
16
+ /** Label height (optional for receipt/continuous mode) */
17
+ height?: number;
18
+ /** Unit of measurement (default: "mm") */
19
+ unit?: Unit;
20
+ /** Printer DPI (default: 203) */
21
+ dpi?: number;
22
+ /** Gap between labels in mm (label printers only) */
23
+ gap?: number;
24
+ /** Print speed (1-10, printer-dependent) */
25
+ speed?: number;
26
+ /** Print darkness/density (0-15) */
27
+ density?: number;
28
+ /** Print direction */
29
+ direction?: 0 | 1;
30
+ /** Number of copies */
31
+ copies?: number;
32
+ }
33
+ /** Text element options */
34
+ interface TextOptions {
35
+ /** X position */
36
+ x?: number;
37
+ /** Y position */
38
+ y?: number;
39
+ /** Font name or ID */
40
+ font?: string;
41
+ /** Font size or magnification */
42
+ size?: number;
43
+ /** Horizontal magnification (1-10) */
44
+ xScale?: number;
45
+ /** Vertical magnification (1-10) */
46
+ yScale?: number;
47
+ /** Rotation */
48
+ rotation?: Rotation;
49
+ /** Bold */
50
+ bold?: boolean;
51
+ /** Underline */
52
+ underline?: boolean;
53
+ /** Reverse (white on black) */
54
+ reverse?: boolean;
55
+ /** Alignment */
56
+ align?: Alignment;
57
+ /** Max width for word-wrap (in dots) */
58
+ maxWidth?: number;
59
+ /** Line spacing (in dots) */
60
+ lineSpacing?: number;
61
+ }
62
+ /** Image element options */
63
+ interface ImageOptions {
64
+ /** X position */
65
+ x?: number;
66
+ /** Y position */
67
+ y?: number;
68
+ /** Target width in dots (auto-scale if set) */
69
+ width?: number;
70
+ /** Target height in dots (auto-scale if set) */
71
+ height?: number;
72
+ /** Dithering algorithm (default: "threshold") */
73
+ dither?: DitherAlgorithm;
74
+ /** Threshold for monochrome conversion (0-255, default: 128) */
75
+ threshold?: number;
76
+ }
77
+ /** Box/rectangle element options */
78
+ interface BoxOptions {
79
+ /** X position */
80
+ x: number;
81
+ /** Y position */
82
+ y: number;
83
+ /** Width */
84
+ width: number;
85
+ /** Height */
86
+ height: number;
87
+ /** Border thickness in dots (default: 1) */
88
+ thickness?: number;
89
+ /** Corner radius in dots */
90
+ radius?: number;
91
+ }
92
+ /** Line element options */
93
+ interface LineOptions {
94
+ /** Start X */
95
+ x1: number;
96
+ /** Start Y */
97
+ y1: number;
98
+ /** End X */
99
+ x2: number;
100
+ /** End Y */
101
+ y2: number;
102
+ /** Line thickness in dots (default: 1) */
103
+ thickness?: number;
104
+ }
105
+ /** Circle element options */
106
+ interface CircleOptions {
107
+ /** Center X */
108
+ x: number;
109
+ /** Center Y */
110
+ y: number;
111
+ /** Diameter in dots */
112
+ diameter: number;
113
+ /** Border thickness in dots (default: 1) */
114
+ thickness?: number;
115
+ }
116
+ /** 1-bit monochrome bitmap (universal intermediate format for images) */
117
+ interface MonochromeBitmap {
118
+ /** Packed 1-bit pixel data, row-major, MSB-first */
119
+ data: Uint8Array;
120
+ /** Width in pixels */
121
+ width: number;
122
+ /** Height in pixels */
123
+ height: number;
124
+ /** Bytes per row = ceil(width / 8) */
125
+ bytesPerRow: number;
126
+ }
127
+ /** Ellipse element options */
128
+ interface EllipseOptions {
129
+ x: number;
130
+ y: number;
131
+ width: number;
132
+ height: number;
133
+ thickness?: number;
134
+ }
135
+ /** Reverse region options (invert black/white) */
136
+ interface ReverseOptions {
137
+ x: number;
138
+ y: number;
139
+ width: number;
140
+ height: number;
141
+ }
142
+ /** Erase region options (clear to white) */
143
+ interface EraseOptions {
144
+ x: number;
145
+ y: number;
146
+ width: number;
147
+ height: number;
148
+ }
149
+ /** Internal label element union type */
150
+ type LabelElement = {
151
+ type: "text";
152
+ content: string;
153
+ options: TextOptions;
154
+ } | {
155
+ type: "image";
156
+ bitmap: MonochromeBitmap;
157
+ options: ImageOptions;
158
+ } | {
159
+ type: "box";
160
+ options: BoxOptions;
161
+ } | {
162
+ type: "line";
163
+ options: LineOptions;
164
+ } | {
165
+ type: "circle";
166
+ options: CircleOptions;
167
+ } | {
168
+ type: "ellipse";
169
+ options: EllipseOptions;
170
+ } | {
171
+ type: "reverse";
172
+ options: ReverseOptions;
173
+ } | {
174
+ type: "erase";
175
+ options: EraseOptions;
176
+ } | {
177
+ type: "raw";
178
+ content: string | Uint8Array;
179
+ };
180
+ /** Resolved label configuration with computed values */
181
+ interface ResolvedLabel {
182
+ /** Width in dots */
183
+ widthDots: number;
184
+ /** Height in dots (0 for continuous/receipt) */
185
+ heightDots: number;
186
+ /** DPI */
187
+ dpi: number;
188
+ /** Gap in dots */
189
+ gapDots: number;
190
+ /** Speed */
191
+ speed: number;
192
+ /** Density */
193
+ density: number;
194
+ /** Direction */
195
+ direction: 0 | 1;
196
+ /** Copies */
197
+ copies: number;
198
+ /** All elements to render */
199
+ elements: LabelElement[];
200
+ }
201
+ //#endregion
202
+ export { EllipseOptions as a, LabelConfig as c, MonochromeBitmap as d, ResolvedLabel as f, Unit as g, TextOptions as h, DitherAlgorithm as i, LabelElement as l, Rotation as m, BoxOptions as n, EraseOptions as o, ReverseOptions as p, CircleOptions as r, ImageOptions as s, Alignment as t, LineOptions as u };