Návod k editaci JSON šablon pro štítky (labels)

Obsah

  1. Úvod
  2. Struktura JSON šablony
  3. Layout — rozložení štítků
  4. Data — zdroj dat
  5. Calibration — kalibrace tiskárny
  6. Content — obsah štítku
  7. Textový blok
  8. Čárový kód
  9. Čára a obdélník 9a. Obrázek 9b. QR kód 9c. Rotace 9d. ShrinkFont — automatické zmenšení fontu
  10. Placeholdery a formáty
  11. Příklady kompletních šablon
  12. Konverze z FoxPro LBX
  13. FoxPro použití
  14. Řešení problémů

1. Úvod

Label renderer generuje PDF se štítky ve dvou režimech:

Obsah štítku se definuje jako pole bloků s absolutní pozicí (v mm) uvnitř jednoho štítku. Podporované bloky: text, čárový kód, čára, obdélník, obrázek, QR kód.

⚠️ HTML = náhled, PDF = tisk. HTML preview slouží k rychlé kontrole rozložení při editaci šablony ve VS Code. Pro tisk vždy generujte PDF — HTML preview má odchylky v rozměrech způsobené scalingem prohlížeče a bitmapovými čárovými kódy. V HTML náhledu se zobrazuje vodoznak „NÁHLED — PRO TISK POUŽIJTE PDF".

Důležité: Všechny rozměry a pozice v JSON jsou v milimetrech. Počátek (0,0) je levý horní roh štítku.


2. Struktura JSON šablony

{
  "renderer": "label",
  "layout": { ... },
  "data": { ... },
  "calibration": { ... },
  "defaultFont": "Segoe UI",
  "content": [ ... ]
}
Sekce Povinná Popis
renderer Ano Vždy "label"
layout Ano Rozměry štítku a rozložení na archu
data Ano Odkaz na XML element s daty
calibration Ne Korekce tiskárny, debug mód
defaultFont Ne Výchozí font (default: "Segoe UI")
content Ano Pole bloků uvnitř štítku

3. Layout — rozložení štítků

Sheet mód (arch)

{
  "layout": {
    "type": "sheet",
    "pageSize": "A4",
    "columns": 3,
    "rows": 8,
    "labelWidth": 63.5,
    "labelHeight": 33.9,
    "marginTop": 13,
    "marginLeft": 5,
    "gapX": 2.5,
    "gapY": 0,
    "startPosition": 1
  }
}
Vlastnost Popis
columns Počet sloupců na archu
rows Počet řádků na archu
labelWidth Šířka jednoho štítku v mm
labelHeight Výška jednoho štítku v mm
marginTop Horní okraj archu v mm
marginLeft Levý okraj archu v mm
gapX Mezera mezi sloupci v mm
gapY Mezera mezi řádky v mm
startPosition Od které pozice tisknout (1-based). Pro načatý arch: 5 = začne od 5. pozice, první 4 jsou prázdné.

Roll mód (pás)

{
  "layout": {
    "type": "roll",
    "labelWidth": 100,
    "labelHeight": 80
  }
}

U pásu stačí zadat šířku a výšku. Každý štítek je samostatná PDF stránka — tiskárna kalibruje automaticky.


4. Data — zdroj dat

{
  "data": {
    "element": "zbozi",
    "copiesField": "pocet_stitku",
    "where": "typ=A"
  }
}
Vlastnost Popis
element Název XML elementu s daty (kontejner s <row> potomky)
copiesField Pole na řádku s počtem kopií (např. "3" → 3 stejné štítky)
copies Fixní počet kopií per řádek (default: 1)
where Filtr: "typ=A" (rovnost), "!pole" (prázdné), "pole" (neprázdné)

XML struktura dat

<root>
  <zbozi>
    <row nazev="Jablka" kod="JAB001" ean="8590123456789" cena="45.90" />
    <row nazev="Hrušky" kod="HRU002" ean="8590123456790" cena="62.50" />
  </zbozi>
</root>

5. Calibration — kalibrace tiskárny

{
  "calibration": {
    "xOffset": 0.5,
    "yOffset": -0.3,
    "showBorders": true
  }
}

Tip: Zapněte showBorders: true, vytiskněte jeden arch a změřte odchylky. Pak nastavte xOffset/yOffset a vypněte debug.

Všechny tři hodnoty mohou být řízeny z XML dat přes placeholdery:

{
  "calibration": {
    "xOffset": "{parametr.cal_x}",
    "yOffset": "{parametr.cal_y}",
    "showBorders": "{parametr.debug}"
  }
}

6. Content — obsah štítku

{
  "content": [
    { "type": "rect", "x": 0, "y": 0, "width": 63.5, "height": 33.9, "fill": "#f8f8f8" },
    { "type": "text", "x": 2, "y": 2, "width": 59, "height": 8, "field": "nazev" },
    { "type": "barcode", "x": 5, "y": 14, "width": 53, "height": 10, "field": "ean" }
  ]
}

Pořadí bloků v poli = pořadí vykreslování (z-index). Obdélník s pozadím dejte na začátek (pod text), text na konec (navrch).

Všechny souřadnice jsou relativní k levému hornímu rohu štítku, ne k archu.


7. Textový blok

{
  "type": "text",
  "x": 2, "y": 1.5, "width": 59, "height": 7,
  "field": "nazev",
  "fontSize": 9,
  "style": "bold",
  "align": "center",
  "maxLines": 2
}
Vlastnost Výchozí Popis
field Pole z XML
template Šablona: "{nazev} ({kod})". Má přednost před field.
format Formát: "N2" (2 des. místa), "dd.MM.yyyy", "###.###" (text maska)
fontSize 8 Velikost v pt
style "normal" "bold", "italic", "bold-italic"
align "left" "left", "center", "right"
valign "top" "top", "center", "bottom"
wordWrap true Zalamování slov (automaticky přes PdfSharp XTextFormatter)
maxLines 0 Maximální počet řádků (0 = bez limitu)
color "black" Barva textu: "red", "#FF0000"
background Barva pozadí boxu
visibleWhen Zobrazit jen když pole není prázdné: "ean", "!sleva"

8. Čárový kód

{
  "type": "barcode",
  "x": 5, "y": 14, "width": 53, "height": 10,
  "field": "ean",
  "format": "EAN13",
  "showText": true,
  "quietZone": 2,
  "visibleWhen": "ean"
}
Vlastnost Výchozí Popis
field Pole s hodnotou kódu
format "EAN13" "EAN13", "EAN8", "Code128", "Code39", "ITF14", "UPCA"
showText true Zobrazit čísla pod čárovým kódem
textFontSize 7 Velikost textu pod kódem
quietZone 2 Bílý prostor kolem kódu v mm (nutný pro spolehlivé skenování)

Důležité: Čárové kódy jsou vektorové (ne bitmapové) — ostré čáry na jakémkoli DPI. Pokud je pole prázdné, kód se automaticky přeskočí.

EAN-13 — automatické doplnění

EAN-13 vyžaduje 12 nebo 13 číslic. Kratší řetězec se automaticky doplní zleva nulami.

EAN-13 a EAN-8 mají automaticky delší guard bars (start, center, end čáry) — standardní vzhled.

Dynamický formát čárového kódu

Pokud data obsahují mix EAN-13 a Code128, formát lze řídit podmínkou:

{
  "type": "barcode",
  "field": "bar_kod",
  "format": "{ean=true?EAN13:Code128}",
  "showText": true,
  "visibleWhen": "bar_kod"
}

Ternární výraz {pole=hodnota?ano:ne} se vyhodnotí per řádek z XML dat.


9. Čára a obdélník

Čára

{ "type": "line", "x": 2, "y": 25, "width": 59, "style": "thin" }

Obdélník

{ "type": "rect", "x": 0, "y": 0, "width": 63.5, "height": 33.9, "border": "#000", "fill": "#f0f0f0", "rounded": 1 }

9a. Obrázek

{ "type": "image", "x": 50, "y": 2, "width": 12, "height": 12, "file": "{parametr.logo}", "fit": "contain" }
Vlastnost Výchozí Popis
file Cesta k souboru nebo {field} placeholder (např. "{parametr.logo}")
fit "contain" "contain" = zachovat poměr stran a centrovat, "stretch" = vyplnit celý box

Tip: contain je ideální pro loga (zachová proporce). stretch použijte pokud chcete vyplnit celý box (např. pozadí).


9b. QR kód

{ "type": "qr", "x": 70, "y": 55, "width": 20, "height": 20,
  "template": "https://example.com/{kod}", "quietZone": 1 }
Vlastnost Výchozí Popis
field Pole z XML s hodnotou pro QR
template Šablona s placeholdery: "SPD*1.0*ACC:{ucet}*AM:{castka}"
quietZone 1 Bílý prostor kolem QR v mm

9c. Rotace

Bloky text, barcode, image a qr lze otočit o 90°, 180° nebo 270°:

{ "type": "text", "x": 55, "y": 14, "width": 5, "height": 20,
  "field": "popis", "fontSize": 7, "rotate": 90 }
Vlastnost Výchozí Popis
rotate 0 Úhel: 0, 90, 180, 270 (stupně po směru hodinových ručiček)

Jak fungují souřadnice

Souřadnice x, y, width, height v JSON vždy popisují výsledný box — tak, jak ho vidíte na vytištěném štítku. Rotace se provádí kolem středu boxu. Interně se pro 90°/270° automaticky prohodí šířka a výška.

Příklad: x=55, y=5, width=5, height=25, rotate=90

Na štítku vidíte:             Interně (před rotací):
┌─────┐                      ┌─────────────────────────┐
│  T  │  5×25mm              │  T E X T                │  25×5mm
│  E  │  úzký box            │                         │  široký box
│  X  │  text rotovaný       └─────────────────────────┘  rotovaný CSS/PdfSharp
│  T  │  90° CW                                           kolem středu
└─────┘

Důležité: Bloky line a rect rotaci nepodporují. Pro otočenou čáru použijte vertikální/horizontální variantu (nastavením width/height).

Rotace funguje i na čárovém kódu — pro vertikální barcode na boku štítku:

{ "type": "barcode", "x": 55, "y": 2, "width": 5, "height": 30,
  "field": "ean", "format": "EAN13", "showText": true, "rotate": 90 }

9d. ShrinkFont — automatické zmenšení fontu

Pro texty s variabilní délkou — automaticky zmenší font pokud se text nevejde do boxu:

{ "type": "text", "x": 2, "y": 2, "width": 59, "height": 7,
  "field": "nazev", "fontSize": 14, "overflow": "shrinkFont" }
Vlastnost Výchozí Popis
overflow "clip" "clip" = oříznutí textu, "shrinkFont" = zmenšení fontu

Jak to funguje:

  1. Začne na fontSize z JSON (např. 14pt)
  2. Změří text — pokud se nevejde, zmenší o 0.5pt
  3. Opakuje dokud se text vejde nebo dosáhne minima 4pt
  4. Funguje s jednořádkovým i víceřádkovým textem (wordWrap)

⚠️ ShrinkFont funguje pouze v PDF. HTML preview tuto funkci nepodporuje — slouží jen k orientační kontrole rozložení.

Typické použití: Dlouhé názvy produktů — nastavte velký fontSize (12–14pt) jako ideál a overflow: "shrinkFont". Krátké názvy se zobrazí velkým písmem, dlouhé se automaticky zmenší.


10. Placeholdery a formáty

V template i field fungují stejné placeholdery jako v tabulkových sestavách:

Syntax Příklad Popis
{pole} {nazev} Hodnota z XML řádku
{pole:format} {cena:N2} S formátem (2 des. místa)
{element.pole} {parametr.firma} Tečková notace (z jiného elementu)
{a\|b\|'text'} {nazev_en\|nazev\|'Bez názvu'} Coalesce — první neprázdná
{pole:UPPER} {kod:UPPER} Velká písmena
{podm?ano:ne} {ean=true?EAN13:Code128} Ternární — podmíněný text per řádek

11. Příklady kompletních šablon

Ceníkový štítek 3×8 na A4

{
  "renderer": "label",
  "layout": {
    "type": "sheet", "pageSize": "A4",
    "columns": 3, "rows": 8,
    "labelWidth": 63.5, "labelHeight": 33.9,
    "marginTop": 13, "marginLeft": 5,
    "gapX": 2.5, "gapY": 0
  },
  "data": { "element": "zbozi" },
  "content": [
    { "type": "text", "x": 2, "y": 2, "width": 59, "height": 7,
      "field": "nazev", "fontSize": 9, "style": "bold", "align": "center", "maxLines": 2 },
    { "type": "text", "x": 2, "y": 10, "width": 35, "height": 4,
      "template": "Kód: {kod}", "fontSize": 7 },
    { "type": "barcode", "x": 5, "y": 15, "width": 53, "height": 10,
      "field": "ean", "format": "EAN13", "visibleWhen": "ean" },
    { "type": "line", "x": 2, "y": 26, "width": 59, "style": "thin" },
    { "type": "text", "x": 2, "y": 27, "width": 40, "height": 5,
      "template": "{cena:N2} Kč/{mj}", "fontSize": 12, "style": "bold" }
  ]
}

Akční štítek s barevným pozadím

{
  "renderer": "label",
  "layout": { "type": "sheet", "columns": 3, "rows": 4,
    "labelWidth": 63.5, "labelHeight": 60, "marginTop": 15, "marginLeft": 8, "gapX": 3 },
  "data": { "element": "zbozi", "where": "typ=A" },
  "content": [
    { "type": "rect", "x": 0, "y": 0, "width": 63.5, "height": 60, "fill": "#fff8e0" },
    { "type": "text", "x": 3, "y": 3, "width": 57, "height": 6,
      "template": "★ AKCE", "fontSize": 10, "style": "bold", "color": "red", "align": "center" },
    { "type": "text", "x": 3, "y": 12, "width": 57, "height": 10,
      "field": "nazev", "fontSize": 11, "style": "bold", "align": "center" },
    { "type": "text", "x": 3, "y": 30, "width": 57, "height": 12,
      "template": "{cena:N2} Kč", "fontSize": 18, "style": "bold", "align": "center" },
    { "type": "text", "x": 3, "y": 45, "width": 57, "height": 8,
      "template": "SLEVA {sleva}%", "fontSize": 12, "style": "bold", "color": "red",
      "align": "center", "visibleWhen": "sleva" }
  ]
}

Paletový štítek (roll 100×80mm)

{
  "renderer": "label",
  "layout": { "type": "roll", "labelWidth": 100, "labelHeight": 80 },
  "data": { "element": "palety" },
  "content": [
    { "type": "rect", "x": 1, "y": 1, "width": 98, "height": 78, "border": "#000" },
    { "type": "text", "x": 3, "y": 3, "width": 94, "height": 8,
      "field": "firma", "fontSize": 12, "style": "bold", "align": "center" },
    { "type": "barcode", "x": 8, "y": 15, "width": 84, "height": 22,
      "field": "sscc", "format": "Code128", "showText": true },
    { "type": "text", "x": 3, "y": 48, "width": 60, "height": 8,
      "template": "Množství: {mnozstvi} {mj}", "fontSize": 11, "style": "bold" }
  ]
}

12. Konverze z FoxPro LBX

Stávající FoxPro LBX štítky (CENK3X8.xml, ADR_2X6.xml, STITEK128.xml atd.) lze automaticky konvertovat na JSON:

*--- Konverze jednoho souboru ---
loBuilder.ConvertLbxToJsonFile("CENK3X8.xml", "cenk3x8.json")

*--- Do složky ---
loBuilder.ConvertLbxToAllFiles("CENK3X8.xml", "C:\output\")

*--- Nebo přes obecnou metodu (auto-detekce LBX z objcode=53) ---
loBuilder.ConvertFrxToJsonFile("CENK3X8.xml", "cenk3x8.json")

Konvertor automaticky rozpozná:

Tip: Po konverzi zkontrolujte JSON a upravte element (datový zdroj), případně layout rozměry.


13. FoxPro použití

Příprava XML dat

loBuilder = CREATEOBJECT("XmlStackBuilder.Core.XmlStackBuilder")
loBuilder.CreateRoot("root")

*--- Header s parametry ---
loBuilder.Push("parametr")
loBuilder.AddAttribute("firma", "EFES spol. s r.o.")
loBuilder.AddAttribute("logo", "C:\images\logo.png")
loBuilder.Pop()

*--- Datové řádky pro štítky ---
CURSORTOXML("tmpStitky", "lcXml", 3, 16)
loBuilder.AddElementWithXmlContent("zbozi", m.lcXml)

*--- Render ---
loBuilder.Render("stitky.pdf", "cenikove_stitky.json")

Tisk na načatý arch

*--- Pokud arch má spotřebovaných 4 štítků ---
* V JSON: "startPosition": 5
* Nebo dynamicky přes parametr:
loBuilder.Push("parametr")
loBuilder.AddAttribute("start", TRANSFORM(lnPocetSpotrebovanych + 1))
loBuilder.Pop()

* V JSON: "startPosition": "{parametr.start}"

Kopie per řádek

*--- Každý řádek má pole "pocet_stitku" ---
* V JSON: "copiesField": "pocet_stitku"
* Řádek s pocet_stitku=3 → 3 stejné štítky

14. Řešení problémů

Štítky jsou posunuté

  1. Zapněte "showBorders": true v calibration
  2. Vytiskněte arch a změřte odchylku
  3. Nastavte "xOffset" a "yOffset" (kladné = posun doprava/dolů)
  4. Vypněte showBorders

Čárový kód se nezobrazuje

Text je oříznutý

PDF je prázdné

Formát čísla je špatný