đ portakal_flutter
Universal printer language SDK for Flutter & Dart â TSC, ZPL, EPL, ESC/POS, CPCL, DPL, IPL, SBPL, Star PRNT and more.
Text, images, printer-native barcode/QR commands, and Flutter preview widgets.
Note: Barcode/QR generation is NOT in this package. Use
etiketfor barcode & QR code generation (SVG/PNG). Portakal sends printer-native barcode/QR commands (the printer's built-in encoder) OR accepts pre-rendered images for pixel-perfect output.
Features
- đ¨ī¸ 9 printer languages â TSC, ZPL, EPL, ESC/POS, CPCL, DPL, IPL, SBPL, Star PRNT
- đ Cross-compilation â convert between any supported languages
- đˇī¸ Fluent label builder â design labels with a clean, chainable API
- đ HTML-like markup â
<label><text>Hello</text></label>DSL - đ Parsers â parse raw printer commands back to structured data
- đī¸ SVG preview â render labels as SVG strings for visual inspection
- đą Flutter preview widget â preview labels in-app before sending to printer
- â Validation â check command ordering, parameter ranges, and structure
- đŧī¸ Image processing â RGBA to monochrome with 4 dithering algorithms
- đ 17 printer profiles â Epson, Zebra, TSC, Star, Bixolon, Citizen, SATO, Honeywell
- đ¯ Works across Flutter targets â mobile, desktop, and web
Installation
dependencies:
portakal_flutter: ^0.1.6
Example
dart run example/main.dart
flutter run -t example/flutter_preview.dart
Quick Start
Build & compile a label
import 'package:portakal_flutter/portakal_flutter.dart';
// Build a label with the fluent API
final myLabel = label(LabelConfig(width: 40, height: 30, unit: Unit.mm))
.text('Hello World', TextOptions(x: 10, y: 10, font: '2', size: 2))
.box(BoxOptions(x: 5, y: 5, width: 310, height: 230, thickness: 2))
.circle(CircleOptions(x: 250, y: 150, diameter: 60));
// Compile to TSC
final tscCode = tsc.compile(myLabel);
// SIZE 40 mm,30 mm
// GAP 3 mm,0 mm
// CLS
// TEXT 10,10,"2",0,2,2,"Hello World"
// BOX 5,5,315,235,2
// CIRCLE 250,150,60,1
// PRINT 1
// Same label â ZPL
final zplCode = zpl.compile(myLabel);
// ^XA
// ^FO10,10^A0N,60,60^FDHello World^FS
// ^FO5,5^GB310,230,2^FS
// ^FO250,150^GC60,1^FS
// ^XZ
HTML-like markup
import 'package:portakal_flutter/portakal_flutter.dart';
final code = tsc.compile(markup('''
<label width="100mm" height="150mm" dpi="203">
<text x="10" y="10" size="2" bold>FROM: Warehouse A</text>
<text x="10" y="40" size="3" bold>TO: John Doe</text>
<text x="10" y="80">123 Main St, New York, NY 10001</text>
<line x1="5" y1="110" x2="780" y2="110" thickness="2" />
<box x="5" y="5" width="780" height="1170" border="3" />
</label>
'''));
Cross-compilation
import 'package:portakal_flutter/portakal_flutter.dart';
// Convert TSC code to ZPL
final result = convert(tscCode, 'tsc', 'zpl');
print(result.output); // ZPL string
// Convert ZPL to ESC/POS (binary)
final receipt = convert(zplCode, 'zpl', 'escpos');
print(receipt.output); // Uint8List
Parse printer commands
import 'package:portakal_flutter/portakal_flutter.dart';
// Parse TSC
final tscResult = tsc.parse('SIZE 40 mm,30 mm\nCLS\nTEXT 10,10,"2",0,1,1,"Hello"\nPRINT 1');
print(tscResult.commands.length); // 4
print(tscResult.widthDots); // 320
print(tscResult.elements.length); // 1 (TextElement)
// Parse ZPL
final zplResult = zpl.parse('^XA^FO10,10^A0N,30,30^FDHello^FS^XZ');
print(zplResult.commands.length); // 6
SVG preview
import 'package:portakal_flutter/portakal_flutter.dart';
final svg = tsc.preview(
label(LabelConfig(width: 40, height: 30))
.text('Preview Test', TextOptions(x: 10, y: 10, size: 2))
.box(BoxOptions(x: 5, y: 5, width: 310, height: 230, thickness: 2)),
);
// Returns SVG string â render in a WebView or save to file
Flutter widget preview
import 'package:flutter/material.dart';
import 'package:portakal_flutter/portakal_flutter.dart';
class LabelPreviewCard extends StatelessWidget {
const LabelPreviewCard({super.key});
@override
Widget build(BuildContext context) {
final myLabel = label(LabelConfig(width: 40, height: 30))
.text('Preview before print', TextOptions(x: 12, y: 20, size: 2))
.box(BoxOptions(x: 8, y: 8, width: 300, height: 200, thickness: 2));
return Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: LabelPreview(label: myLabel),
),
);
}
}
Validate commands
import 'package:portakal_flutter/portakal_flutter.dart';
// Validate TSC
final r = tsc.validate('SIZE 40 mm,30 mm\nCLS\nTEXT 10,10,"2",0,1,1,"Hi"\nPRINT 1');
print(r.valid); // true
print(r.errors); // 0
// Catch errors
final bad = tsc.validate('TEXT 10,10,"2",0,1,1,"No CLS"\nPRINT 1');
print(bad.valid); // false
print(bad.issues); // [CLS must appear before label elements]
Image processing
import 'dart:typed_data';
import 'package:portakal_flutter/portakal_flutter.dart';
// Convert RGBA pixels to monochrome bitmap
final rgba = Uint8List(100 * 100 * 4); // 100x100 RGBA image
final bitmap = imageToMonochrome(rgba, 100, 100);
// bitmap.data â 1-bit packed bitmap
// bitmap.bytesPerRow â bytes per scanline
// Use with label builder
final myLabel = label(LabelConfig(width: 40, height: 30))
.image(bitmap, ImageOptions(x: 10, y: 10));
Printer profiles
import 'package:portakal_flutter/portakal_flutter.dart';
// Get a specific profile
final profile = getProfile('zebra-zd420');
print(profile?.dpi); // 203
print(profile?.language); // zpl
print(profile?.dotsPerLine); // 864
// Find by USB vendor ID
final epsonPrinters = findByVendorId(0x04B8);
// Find by language
final zplPrinters = findByLanguage('zpl');
// Use with label builder â auto-sets DPI
final myLabel = label(LabelConfig(
width: 40, height: 30,
printer: 'tsc-te310', // Uses 300 DPI from profile
));
Receipt formatting (ESC/POS)
import 'package:portakal_flutter/portakal_flutter.dart';
// Format a receipt line
final line = formatPair('Hamburger', '\$12.99', 32);
// "Hamburger $12.99"
// Word wrap
final lines = wordWrap('This is a long text that needs wrapping', 20);
// ["This is a long text", "that needs wrapping"]
// Table
final rows = formatTable(
[Column(width: 20), Column(width: 8, align: 'right'), Column(width: 4, align: 'right')],
[['Hamburger', '\$12.99', 'x2'], ['Fries', '\$4.99', 'x1']],
32,
);
Supported Languages
| Language | Compile | Parse | Preview | Validate |
|---|---|---|---|---|
| TSC/TSPL2 | â | â | â | â Full |
| ZPL II | â | â | â | â Full |
| EPL2 | â | â | â | âšī¸ Basic |
| ESC/POS | â | â | â | âšī¸ Basic |
| CPCL | â | â | â | âšī¸ Basic |
| DPL | â | â | â | âšī¸ Basic |
| IPL | â | â | â | âšī¸ Basic |
| SBPL | â | â | â | âšī¸ Basic |
| Star PRNT | â | â | â | âšī¸ Basic |
Label Elements
| Element | Description | TSC | ZPL | EPL | ESC/POS | CPCL | DPL | IPL | SBPL | Star PRNT |
|---|---|---|---|---|---|---|---|---|---|---|
text |
Text with font, size, rotation | â | â | â | â | â | â | â | â | â |
image |
Monochrome bitmap | â | â | â | â | â | â | â | â | â |
box |
Rectangle with optional radius | â | â | â | â | â | â | â | â | â |
line |
Line between two points | â | â | â ī¸ | â | â | â ī¸ | â ī¸ | â ī¸ | â |
circle |
Circle with thickness | â | â | â | â | â | â | â | â | â |
ellipse |
Ellipse | â | â | â | â | â | â | â | â | â |
reverse |
Invert colors in region | â | â | â | â | â | â | â | â | â |
erase |
Clear region to white | â | â | â | â | â | â | â | â | â |
raw |
Raw command passthrough | â | â | â | â | â | â | â | â | â |
â ī¸ indicates a best-effort approximation (for example, non-diagonal-only line behavior).
Dithering Algorithms
Four algorithms for converting images to 1-bit monochrome:
| Algorithm | Best For |
|---|---|
threshold |
Simple graphics, logos, barcodes |
floydSteinberg |
Photos, gradients (best quality) |
atkinson |
Retro aesthetic, lighter output |
ordered |
Fast, predictable patterns |
API Reference
Language Modules
Each language module (tsc, zpl, epl, escpos, cpcl, dpl, ipl, sbpl, starprnt) exports:
String compile(LabelBuilder builder) // Label â printer commands
Result parse(String code) // Printer commands â structured data
String preview(LabelBuilder builder) // Label â SVG string
Result validate(String code) // Check command validity
Core Functions
LabelBuilder label(LabelConfig config) // Create label builder
LabelBuilder markup(String source) // Parse HTML-like markup
ConvertResult convert(String code, String from, String to, {...}) // Cross-compile
String renderPreview(ResolvedLabel label) // SVG preview
Result validate(String code, String language) // Validate commands
Development
# Run tests
dart test
# Run a specific test
dart test test/tsc_test.dart
# Static analysis
dart analyze
Credits
Dart/Flutter port of portakal by productdevbook.
License
MIT
Libraries
- portakal_flutter
- Portakal Flutter â Universal printer language SDK.