メインコンテンツにスキップ
バージョン: 1.x

サーマルプリンターテンプレート

サーマルテンプレートは XML 形式を使用し、同じテンプレートから画面プレビューと ESC/POS プリンターコマンドの両方を生成します。データバインディングには HTML テンプレート と同じ {{variable}} プレースホルダーを使います。

プリンター設定で接続されたレシートプリンターがある場合は、このエンジンを選択してください。

XML 要素

ルート要素

すべてのサーマルテンプレートは <receipt> ルートから始まります。

<receipt paper-width="48">
<!-- 48 characters = 80mm paper -->
<!-- 32 characters = 58mm paper -->
</receipt>

テキストと書式

<text>Plain text</text>
<bold>Bold text</bold>
<underline>Underlined text</underline>
<invert>Inverted (white on black)</invert>

配置

<align mode="left">Left aligned</align>
<align mode="center">Centered</align>
<align mode="right">Right aligned</align>

文字サイズ

文字の幅と高さを個別に拡大できます。

<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>

表形式レイアウト

揃った列には <row><col> を使います。

<row>
<col width="24">Item name</col>
<col width="8" align="right">Qty</col>
<col width="16" align="right">Price</col>
</row>

列幅は文字数です。残りの幅を吸収する柔軟な列には width="*" を使います。これにより、用紙幅が違ってもテンプレートを変更せずに利用できます。

<row>
<col width="*">{{name}}</col>
<col width="12" align="right">{{line_total_display}}</col>
</row>

区切り線と余白

<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/>(または style="single")と style="double" は、プリンターのネイティブ罫線を印刷します。dasheddotted は、現在の列幅全体に文字ベースの区切りを印刷します。サーマルプレビューのスクリーンショットでも見える区切りが必要な場合に便利です。

プリンターコマンド

<cut /> <!-- Full paper cut -->
<cut mode="partial" /> <!-- Partial cut (leaves a tab) -->
<drawer /> <!-- Open cash drawer -->

バーコードと QR コード

<barcode type="code128" height="40">{{order.number}}</barcode>
<barcode type="qrcode" scale="3">{{fiscal.qr_payload}}</barcode>

例: シンプルな 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>

スター幅の列

width="*" 機能により、テンプレートは用紙幅に依存しにくくなります。特定の用紙サイズに合わせて列幅を固定する代わりに、伸ばしたい列に * を使います。

<!-- 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>

80mm プリンター(48 文字)では商品名に 38 文字が割り当てられます。58mm プリンター(32 文字)では 22 文字です。固定列はどちらでも同じサイズのままです。

テンプレートプレビュー

テンプレートエディターは、編集中にライブサーマルプレビューを表示します。プレビューは XML を等幅 HTML として描画し、紙に印刷されたときの見た目をシミュレートします。変更は短い遅延後(300ms のデバウンス)に更新されます。

同じテンプレートから、プレビューと ESC/POS プリンター出力の両方が生成されます。別の印刷テンプレートは不要です。バーコードと QR コードはプレビューではインライン SVG として、プリンターではネイティブ ESC/POS コマンド(またはラスター画像)として出力されます。

作成時のヒントと落とし穴

サーマル印刷には HTML にはない注意点があります。作成者がよく遭遇するものをまとめます。

改行のため、装飾見出しを <text> で包む

装飾コンテナ — <bold><size><underline><align> — はそれ自体では改行を出力しません。改行を出すのは <text> とブロック要素(<line/><row><feed>)です。

<!-- ❌ 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>

同梱の 80mm ギャラリーテンプレートは、すべての見出しでこのパターンを使っています。

狭い行内で <size width="2"> を避ける

倍幅テキストは実効文字数を2倍にします。80mm プリンターに収まる見出しでも、一般的な 42 列の 80mm プリンターでははみ出すことがあり、58mm 用紙では残りが 16 文字しかありません。

大きな合計やキッチン注文番号などの目立つ値は、複数列の <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>

用紙幅に依存しないレイアウトには width="*" を使う

width="*"(スター)列は、固定幅列の後に残った幅を吸収します。同じテンプレートが、32 列(58mm)、42 列(標準 80mm)、48 列(幅広 80mm)のプリンターで正しく描画されます。

<!-- Works on 58mm AND 80mm without changes -->
<row>
<col width="*">{{name}}</col>
<col width="10" align="right">{{line_total_display}}</col>
</row>

数値の固定幅を使う場合は、48 ではなく 42 を基準に配分してください。合計が 48 になる行は、一般的な 42 列 80mm プリンターで折り返されます。

<align> ブロック内の中央揃え装飾見出し

<align mode="center">(または right)の中では、<bold><size><underline><invert> などの直接の装飾見出しの後に別の行が続くと、その見出しは自動的に独立した行として閉じられます。中央揃えで拡大した店名の下に中央揃えの住所を置いても、明示的な <text> ラップなしで正しく印刷されます。

配置ブロックの外では、<text> ラップを使い続けてください。

ESC/POS 句読点の正規化

プリンター言語が ESC/POS の場合、エンコーダーは書き込み前にタイポグラフィ記号を安全な ASCII に正規化します。

  • en ダッシュ、em ダッシュ、数字ダッシュ、Unicode マイナス → -
  • カーリー引用符 → 直線引用符
  • ノーブレークスペース → 通常のスペース

そのため、Unicode フォントのないプリンターでも Mon–Sat 9:00–18:00"open" は正しく印刷されます。Star プリンター(star-line / star-prnt)は元のタイポグラフィを保持するため、プリンターのフォントが対応する文字で作成してください。

非ラテン文字と右から左の文字

サーマルプリンターは内蔵フォントとコードページで文字を印刷します。アラビア語、ヘブライ語、ペルシア語、ウルドゥー語などの非ラテン文字は、対応するコードページ(例: アラビア語なら CP864 / Windows-1256)に設定されている場合にのみ正しく印刷されます。そうでない場合は空白や文字化けになります。

これらの文字では、レシート全体を画像として描画する Full receipt raster が確実です。プリンター内蔵フォントに依存せず、設計どおりに印刷できます。ラスター方式を有効にするには プリンター設定 を参照してください。

サーマルハードウェアにはサーマルテンプレートが必要です

サーマルプリンターはフルページの HTML テンプレートを印刷できません。ジョブは ESC/POS または Star コマンドに変換される必要があり、HTML ではそれを表現できません。サーマルハードウェアにはサーマルテンプレートを使ってください。A4/Letter のフルページ HTML は、システム/PDF プリンターまたは PrintNode 経由で印刷します。

ロゴと画像

ロゴを埋め込むには <image> を使います。

<align mode="center">
<image src="data:image/png;base64,..." />
</align>

WCPOS はクライアント側で画像をラスター化します。デコードし、透明部分を白で平坦化し、プリンターのドット予算に合わせてリサイズし、モノクロに変換して(ロゴは Atkinson ディザリング、バーコードはしきい値処理)、ESC/POS または Star の画像コマンドを送信します。

  • ドット予算: 58mm は幅 384 ドット、80mm は幅 576 ドット。
  • 利用可能なソース: data:image/pngdata:image/jpeg のデータ URL、絶対 http(s) URL、同一オリジンのルート相対パス。プロトコル相対 //、バックスラッシュ、パーセントエンコードされた .. トラバーサルは拒否されます。
  • 推奨形式: 透明または白背景の高コントラスト PNG。JPEG も使えますが、圧縮ノイズが印刷に出ることがあります。
  • SVG はまだ raw サーマル出力ではサポートされていません

ヒント

  • ギャラリーテンプレートから始める — ギャラリーのサーマルテンプレートは上記のパターンを使い、実機プリンターで検証されています。
  • 店舗で異なるプリンターを使う場合は、両方の用紙サイズをテストするか、width="*" 列を使ってください。
  • 通貨には _display フィールドを使ってください。すでにロケール対応済みです。
  • シンプルに保つ — サーマル印刷は HTML より書式ツールが少ない設計です。<row> + <col width="*"> を中心に使い、プリンターに任せてください。