Modelli per stampanti termiche
I modelli termici usano un formato XML che produce sia un'anteprima a schermo sia comandi per stampanti ESC/POS dallo stesso modello. Usano gli stessi segnaposto {{variable}} dei modelli HTML per il binding dei dati.
Scegli questo motore se hai una stampante per ricevute collegata tramite la configurazione della stampante.
Elementi XML
Elemento radice
Ogni modello termico inizia con un <receipt> radice:
<receipt paper-width="48">
<!-- 48 characters = 80mm paper -->
<!-- 32 characters = 58mm paper -->
</receipt>
Testo e formattazione
<text>Plain text</text>
<bold>Bold text</bold>
<underline>Underlined text</underline>
<invert>Inverted (white on black)</invert>
Allineamento
<align mode="left">Left aligned</align>
<align mode="center">Centered</align>
<align mode="right">Right aligned</align>
Dimensione del testo
Scala larghezza e altezza del testo in modo indipendente:
<size width="2" height="2">Double-size text</size>
<size width="2" height="1">Wide text</size>
<size width="1" height="2">Tall text</size>
Layout tabellare
Utilizzare <row> e <col> per colonne allineate:
<row>
<col width="24">Item name</col>
<col width="8" align="right">Qty</col>
<col width="16" align="right">Price</col>
</row>
Le larghezze delle colonne sono espresse in caratteri. Usa width="*" per una colonna flessibile che assorbe lo spazio rimanente — questo consente ai template di funzionare con diverse larghezze di carta senza modifiche:
<row>
<col width="*">{{name}}</col>
<col width="12" align="right">{{line_total_display}}</col>
</row>
Separatori e spaziatura
<line /> <!-- Default single rule -->
<line style="double" /> <!-- Printer-native double rule -->
<line style="dashed" /> <!-- Character dashes across the width -->
<line style="dotted" /> <!-- Character dots across the width -->
<feed lines="2" /> <!-- Blank lines -->
<line/> (o style="single") e style="double" stampano la linea nativa della stampante. dashed e dotted stampano separatori basati su caratteri su tutta la larghezza della colonna attiva — utile quando si desidera un separatore visibile che rimanga anche in uno screenshot dell'anteprima termica.
Comandi della stampante
<cut /> <!-- Full paper cut -->
<cut mode="partial" /> <!-- Partial cut (leaves a tab) -->
<drawer /> <!-- Open cash drawer -->
Codici a barre e codici QR
<barcode type="code128" height="40">{{order.number}}</barcode>
<barcode type="qrcode" scale="3">{{fiscal.qr_payload}}</barcode>
Esempio: semplice ricevuta da 80mm
<receipt paper-width="48">
<align mode="center">
<size width="2" height="2">{{store.name}}</size>
</align>
<feed lines="1" />
<align mode="center">
<text>{{store.address_1}}</text>
<text>{{store.city}} {{store.state}} {{store.postcode}}</text>
{{#store.phone}}<text>{{store.phone}}</text>{{/store.phone}}
</align>
<line />
<text>Order: #{{order.number}}</text>
<text>Date: {{order.created.datetime}}</text>
{{#cashier.name}}<text>Cashier: {{cashier.name}}</text>{{/cashier.name}}
<line />
<!-- Column headers -->
<row>
<col width="*"><bold>Item</bold></col>
<col width="4" align="right"><bold>Qty</bold></col>
<col width="12" align="right"><bold>Total</bold></col>
</row>
<line />
<!-- Line items -->
{{#lines}}
<row>
<col width="*">{{name}}</col>
<col width="4" align="right">{{qty}}</col>
<col width="12" align="right">{{line_total_display}}</col>
</row>
{{/lines}}
<line />
<!-- Totals -->
<row>
<col width="*">Subtotal</col>
<col width="16" align="right">{{totals.subtotal_display}}</col>
</row>
{{#totals.tax_total}}
<row>
<col width="*">Tax</col>
<col width="16" align="right">{{totals.tax_total_display}}</col>
</row>
{{/totals.tax_total}}
<row>
<col width="*"><bold>TOTAL</bold></col>
<col width="16" align="right"><bold>{{totals.total_display}}</bold></col>
</row>
<line />
{{#payments}}
<row>
<col width="*">{{method_title}}</col>
<col width="16" align="right">{{amount_display}}</col>
</row>
{{#tendered}}
<row>
<col width="*">Tendered</col>
<col width="16" align="right">{{tendered_display}}</col>
</row>
<row>
<col width="*">Change</col>
<col width="16" align="right">{{change_display}}</col>
</row>
{{/tendered}}
{{/payments}}
<feed lines="2" />
<align mode="center">
<text>Thank you for your purchase!</text>
</align>
<feed lines="3" />
<cut />
</receipt>
Colonne con larghezza a stella
La funzionalità width="*" rende i modelli indipendenti dalla larghezza della carta. Invece di codificare larghezze di colonna fisse per un formato carta specifico, usare * per la colonna che deve espandersi:
<!-- Works on 58mm (32 char) AND 80mm (48 char) printers -->
<row>
<col width="*">{{name}}</col>
<col width="10" align="right">{{line_total_display}}</col>
</row>
Su una stampante da 80mm (48 caratteri), il nome dell'articolo riceve 38 caratteri. Su una stampante da 58mm (32 caratteri), riceve 22 caratteri. Le colonne fisse mantengono la stessa dimensione su entrambe.
Anteprima del modello
L'editor del modello mostra un'anteprima termica in tempo reale durante la modifica. L'anteprima renderizza l'XML come HTML monospace stilizzato, simulando l'aspetto della ricevuta su carta. Le modifiche vengono aggiornate dopo un breve ritardo (debounce a 300ms).
Lo stesso modello produce sia l'anteprima sia l'output di stampa ESC/POS: non esiste un modello "di stampa" separato. I codici a barre e i codici QR vengono renderizzati come SVG inline nell'anteprima e come comandi ESC/POS nativi (o immagini raster) sulla stampante.
Suggerimenti di authoring e problemi comuni
La stampa termica presenta alcune insidie che non esistono in HTML. Queste sono quelle che gli autori incontrano più spesso.
Racchiudere le intestazioni stilizzate in <text> per un'interruzione di riga
Contenitori con stile — <bold>, <size>, <underline>, <align> — non generano da soli un'interruzione di riga. Solo <text> e gli elementi di blocco (<line/>, <row>, <feed>) sì.
<!-- ❌ Bug: the heading runs together with whatever follows -->
<bold>{{i18n.bill_to}}</bold>
{{customer.name}}
<!-- ✅ Fix: wrap the inner content in <text> -->
<bold><text>{{i18n.bill_to}}</text></bold>
<text>{{customer.name}}</text>
I modelli della galleria 80mm inclusi usano questo schema per ogni intestazione.
Evitare <size width="2"> nelle righe strette
Il testo a doppia larghezza raddoppia il conteggio effettivo dei caratteri. Un titolo che rientra in una stampante da 80mm può fuoriuscire su una stampante 80mm generica da 42 colonne, e su carta da 58mm lascia solo 16 caratteri.
Per valori in evidenza (totali grandi, numeri degli ordini in cucina), genera una riga scalata autonoma invece di racchiuderli all'interno di un layout a più colonne <row>:
<!-- For store names, prefer normal-width, double-height -->
<bold><size height="2"><text>{{store.name}}</text></size></bold>
<!-- For a bold total, put it on its own line above the row -->
<align mode="right">
<bold><size height="2"><text>{{totals.total_display}}</text></size></bold>
</align>
Usare width="*" per layout indipendenti dalla larghezza della carta
La colonna width="*" (asterisco) assorbe la larghezza rimanente dopo le colonne a larghezza fissa. Lo stesso template viene quindi visualizzato correttamente su stampanti a 32 colonne (58mm), 42 colonne (80mm standard) e 48 colonne (80mm larghe) senza modifiche:
<!-- Works on 58mm AND 80mm without changes -->
<row>
<col width="*">{{name}}</col>
<col width="10" align="right">{{line_total_display}}</col>
</row>
Se usi larghezze numeriche hard-coded, calcolale per 42, non per 48. Le righe la cui somma arriva a 48 andranno a capo sulle comuni stampanti da 80mm a 42 colonne.
Intestazioni con stile centrate all'interno di blocchi <align>
All'interno di <align mode="center"> (o right), un'intestazione stilizzata diretta — <bold>, <size>, <underline>, <invert> inserito direttamente all'interno <align> — seguito da un'altra riga viene chiuso automaticamente sulla propria riga. Un nome del negozio centrato e ridimensionato sopra una riga dell'indirizzo centrata viene stampato in modo pulito anche senza l'esplicito <text> ritorno a capo.
Fuori da un blocco di allineamento, mantenere il <text> ritorno a capo.
Normalizzazione della punteggiatura ESC/POS
Quando il linguaggio della stampante è ESC/POS, l'encoder normalizza la punteggiatura tipografica in ASCII sicuro prima della scrittura:
- Trattino medio, trattino lungo, trattino numerico, segno meno Unicode →
- - Virgolette tipografiche → virgolette dritte
- Spazio unificatore → spazio normale
Così Mon–Sat 9:00–18:00 e "open" vengono stampati correttamente anche su stampanti senza un font Unicode. Le stampanti Star (star-line / star-prnt) preservano la tipografia originale, quindi usare caratteri supportati dal font della stampante.
Scritture non latine e da destra a sinistra
Le stampanti termiche stampano il testo usando un font e una code page integrati, quindi arabo, ebraico, persiano, urdu e altri sistemi di scrittura non latini vengono stampati correttamente solo se la stampante è impostata su una code page corrispondente (ad es. CP864 / Windows-1256 per l'arabo): in caso contrario si ottengono spazi vuoti o caratteri illeggibili.
L'approccio affidabile per questi sistemi di scrittura è raster completo della ricevuta, che rende l'intera ricevuta come immagine, così viene stampata esattamente come progettata, indipendentemente dai font integrati della stampante. Consultare Configurazione della stampante per abilitare la modalità raster.
Una stampante termica non può stampare un template HTML a pagina intera: il lavoro deve essere reso in comandi ESC/POS o Star, cosa che HTML non può esprimere. Utilizzare un template termico per l'hardware termico; per HTML A4/Letter a pagina intera, stampare su una stampante di sistema/PDF o tramite PrintNode.
Loghi e immagini
Utilizzare <image> per incorporare un logo:
<align mode="center">
<image src="data:image/png;base64,..." />
</align>
WCPOS rasterizza le immagini sul client: decodifica, appiattisce la trasparenza sul bianco, ridimensiona in base al budget di punti della stampante, converte in monocromatico (dithering Atkinson per i loghi, soglia per i codici a barre), quindi invia comandi immagine ESC/POS o Star.
- Budget di punti: 384 punti di larghezza per 58mm, 576 punti di larghezza per 80mm.
- Origini accettate: URL di dati
data:image/pngedata:image/jpeg, URL assolutihttp(s)e percorsi relativi alla radice della stessa origine. Sono rifiutati//relativi al protocollo, barre rovesciate e attraversamenti percent-encoded... - Formato consigliato: PNG ad alto contrasto con sfondo trasparente o bianco. JPEG funziona, ma gli artefatti di compressione possono essere stampati come disturbo.
- SVG non e ancora supportato per l'output termico grezzo.
Suggerimenti
- Inizia da un template della galleria — i template termici nella galleria usano tutti i pattern precedenti e sono convalidati su stampanti reali.
- Testa entrambi i formati carta se i tuoi negozi usano stampanti diverse, oppure limitati alle colonne
width="*". - Usa i campi
_displayper la valuta — sono gia adattati alle impostazioni locali. - Mantieni la semplicita — il formato termico offre volutamente meno strumenti di formattazione rispetto all'HTML. Fai affidamento su
<row>+<col width="*">e lascia che la stampante faccia il resto.