Version: 1.0
This document defines the universal label format used by TSC Bridge. Any application that produces labels in this format can use any TSC Bridge driver to print them.
The label format is JSON-based, inspired by pdfme. It describes:
- Page dimensions (label size)
- Field positions and sizes
- Field types (text, barcode, QR code, image, line, rectangle)
- Variable bindings for dynamic data
{
"basePdf": {
"width": 50,
"height": 30
},
"schemas": [
[
{ "name": "field1", "type": "text", ... },
{ "name": "field2", "type": "barcodes128", ... }
]
]
}| Field | Type | Required | Description |
|---|---|---|---|
basePdf |
object | Yes | Label dimensions |
schemas |
array | Yes | Array of page schemas (one per page) |
| Field | Type | Unit | Description |
|---|---|---|---|
width |
number | mm | Label width in millimeters |
height |
number | mm | Label height in millimeters |
An array of arrays. Each inner array represents one page (label) and contains an array of field objects. For single-label templates, there is one inner array.
Plain text rendered at a fixed position.
{
"name": "product_name",
"type": "text",
"position": { "x": 5, "y": 5 },
"width": 40,
"height": 8,
"content": "",
"fontSize": 12,
"fontName": "Helvetica",
"alignment": "left",
"rotation": 0
}| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Unique field identifier |
type |
string | required | Must be "text" |
position |
object | required | { "x": mm, "y": mm } from top-left |
width |
number | required | Field width in mm |
height |
number | required | Field height in mm |
content |
string | "" |
Static text or default value |
fontSize |
number | 10 |
Font size in points |
fontName |
string | "Helvetica" |
Font family |
fontColor |
string | "#000000" |
Text color (hex) |
alignment |
string | "left" |
"left", "center", "right" |
rotation |
number | 0 |
Rotation in degrees (0, 90, 180, 270) |
lineHeight |
number | 1.2 |
Line height multiplier |
Text with multiple variable placeholders. Variables are enclosed in curly
braces: {nombre} {apellido}.
{
"name": "full_info",
"type": "multiVariableText",
"position": { "x": 5, "y": 5 },
"width": 40,
"height": 15,
"content": "{nombre} {apellido}\n{empresa}\n{puesto}",
"variables": ["nombre", "apellido", "empresa", "puesto"],
"fontSize": 10
}Additional fields beyond text:
| Field | Type | Description |
|---|---|---|
variables |
string[] | List of variable names used in content |
Variable resolution: when rendering, the bridge replaces {varname} with the
corresponding value from the row data. If the row uses prefixed keys (e.g.,
gafete_nombre), the bridge matches by suffix.
Code 128 barcode.
{
"name": "product_code",
"type": "barcodes128",
"position": { "x": 5, "y": 15 },
"width": 40,
"height": 10,
"content": ""
}Code 39 barcode. Same structure as barcodes128.
EAN-13 barcode. Input must be 12 or 13 digits.
UPC-A barcode. Input must be 11 or 12 digits.
Interleaved 2 of 5 barcode. Input must be even number of digits.
Codabar barcode.
QR code with configurable content type.
{
"name": "vcard_qr",
"type": "qrcode",
"position": { "x": 35, "y": 5 },
"width": 12,
"height": 12,
"content": "{token}"
}QR content can be:
- Plain text
- URL
- vCard (BEGIN:VCARD...END:VCARD)
- Custom payload with
{variable}placeholders
Raster image from a URL or base64 data.
{
"name": "logo",
"type": "image",
"position": { "x": 2, "y": 2 },
"width": 15,
"height": 15,
"content": "https://example.com/logo.png"
}Content formats: HTTP/HTTPS URL, base64-encoded PNG/JPEG, or data URI.
Horizontal or vertical line.
{
"name": "separator",
"type": "line",
"position": { "x": 0, "y": 14 },
"width": 50,
"height": 0.3
}Rectangular border or filled box.
{
"name": "border",
"type": "rectangle",
"position": { "x": 1, "y": 1 },
"width": 48,
"height": 28,
"strokeWidth": 0.5
}When printing, the application provides row data as key-value pairs:
{
"nombre": "Juan",
"apellido": "Garcia",
"empresa": "Acme Corp",
"codigo": "1234567890"
}The bridge matches row keys to field names using this precedence:
- Exact match:
row["nombre"]for field namednombre - Suffix match:
row["gafete_nombre"]matches fieldnombre - Normalized match:
row["gafete.nombre"]matches fieldgafete_nombre(dots and underscores are interchangeable)
- Origin: top-left corner of the label
- Units: millimeters
- X axis: left to right
- Y axis: top to bottom
- All positions and dimensions are in millimeters
- Drivers convert to dots using:
dots = mm * DPI / 25.4
Common thermal printer DPI values:
| DPI | Dots per mm | Typical use |
|---|---|---|
| 203 | 8 | Standard labels, shipping |
| 300 | ~12 | High-quality labels, badges |
| 600 | ~24 | Ultra-fine print, small labels |
The label format is DPI-independent. Drivers are responsible for converting millimeter values to dots at the target DPI.
This specification follows semantic versioning. The current version is 1.0.
- Patch (1.0.x): Clarifications, typo fixes
- Minor (1.x.0): New field types, new optional properties (backward compatible)
- Major (x.0.0): Breaking changes to existing field types or coordinate system
{
"basePdf": { "width": 100, "height": 60 },
"schemas": [[
{
"name": "recipient",
"type": "text",
"position": { "x": 5, "y": 5 },
"width": 60, "height": 8,
"fontSize": 14, "fontName": "Helvetica-Bold"
},
{
"name": "address",
"type": "multiVariableText",
"position": { "x": 5, "y": 15 },
"width": 60, "height": 20,
"content": "{street}\n{city}, {state} {zip}",
"variables": ["street", "city", "state", "zip"],
"fontSize": 10
},
{
"name": "tracking",
"type": "barcodes128",
"position": { "x": 5, "y": 40 },
"width": 90, "height": 15
}
]]
}{
"basePdf": { "width": 86, "height": 54 },
"schemas": [[
{
"name": "photo",
"type": "image",
"position": { "x": 3, "y": 3 },
"width": 20, "height": 25
},
{
"name": "name",
"type": "text",
"position": { "x": 26, "y": 5 },
"width": 55, "height": 10,
"fontSize": 16, "alignment": "center"
},
{
"name": "company",
"type": "text",
"position": { "x": 26, "y": 17 },
"width": 55, "height": 6,
"fontSize": 10, "alignment": "center"
},
{
"name": "qr",
"type": "qrcode",
"position": { "x": 65, "y": 30 },
"width": 18, "height": 18
}
]]
}{
"basePdf": { "width": 50, "height": 30 },
"schemas": [[
{
"name": "product",
"type": "text",
"position": { "x": 2, "y": 2 },
"width": 46, "height": 6,
"fontSize": 12
},
{
"name": "price",
"type": "text",
"position": { "x": 2, "y": 9 },
"width": 20, "height": 6,
"fontSize": 14, "fontName": "Helvetica-Bold"
},
{
"name": "sku",
"type": "barcodes128",
"position": { "x": 2, "y": 17 },
"width": 46, "height": 10
}
]]
}