ブラウザでの印刷の問題
Webアプリからレシートを印刷しようとしたことがある方なら、その苦労をご存知でしょう。window.print()は印刷ダイアログを開き、ページをPDFとしてレンダリングするため、自動カットやカスタム用紙幅のようなESC/POSコマンドには一切対応していません。
サーマルレシートプリンターにとって、これは致命的です。必要なのは以下の機能です。
- サイレント印刷 — ダイアログなし、ユーザー操作なし
- ESC/POSコマンド — 自動カット、太字、アライメント、バーコード用
- 信頼性の高いエンコーディング — プリンターの正しいコードページへのUTF-8変換
- クロスプラットフォーム対応 — Mac、Windows、Linux
解決策は、ローカルWebSocketブリッジです。これは、ユーザーのコンピューター上で動作する小さなバックグラウンドアプリで、Webアプリから印刷ジョブを受け取り、生のESC/POSコマンドをプリンターに送信します。
WebSocketブリッジの仕組み
Your Web App → WebSocket (ws://localhost:8765) → Print Agent → Thermal Printer
流れはシンプルです。
- Webアプリが
ws://localhost:8765へのWebSocket接続を開きます。 - レシートを記述したJSONペイロードを送信します。
- Print AgentがそれをESC/POSに変換し、プリンターに送信します。
- プリンターはサイレントに印刷します — ダイアログもドライバー操作もありません。
MenuForma Print Agentはこのブリッジを実装しています。無料でオープンソースであり、Mac、Windows、Linuxで動作します。
APIリファレンス
接続
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => {
console.log('Print Agent connected');
};
ws.onerror = () => {
console.log('Print Agent not running');
};
エージェントの状態確認
エージェントが実行中であることを確認するためにpingを送信します。
ws.send(JSON.stringify({ type: 'ping' }));
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'pong') {
console.log('Agent version:', data.version);
}
};
レシートの印刷
const receipt = {
type: 'print',
printer: 'auto', // または '192.168.1.100' のような特定のIP
data: {
storeName: 'My Restaurant',
storeAddress: '123 Main St',
orderNumber: '#1042',
tableNumber: 'Table 5',
items: [
{ name: 'Margherita Pizza', qty: 1, price: 14.90 },
{ name: 'Sparkling Water', qty: 2, price: 3.50 },
],
subtotal: 21.90,
tax: 1.97,
total: 23.87,
paymentMethod: 'Card',
footer: 'Thank you for dining with us!',
}
};
ws.send(JSON.stringify(receipt));
React統合の例
import { useEffect, useRef, useCallback, useState } from 'react';
function usePrintAgent() {
const wsRef = useRef(null);
const [connected, setConnected] = useState(false);
useEffect(() => {
const connect = () => {
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => setConnected(true);
ws.onclose = () => {
setConnected(false);
setTimeout(connect, 3000); // リトライ
};
wsRef.current = ws;
};
connect();
return () => wsRef.current?.close();
}, []);
const print = useCallback((receiptData) => {
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
throw new Error('Print Agent not connected');
}
wsRef.current.send(JSON.stringify({ type: 'print', data: receiptData }));
}, []);
return { connected, print };
}
Shopify統合
Shopifyストアの場合、注文のWebhookまたはブラウザ拡張機能から印刷をトリガーできます。
// Shopifyストアフロントまたは管理拡張機能内
async function printShopifyOrder(order) {
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'print',
data: {
storeName: order.shop_name,
orderNumber: order.name,
items: order.line_items.map(item => ({
name: item.title,
qty: item.quantity,
price: parseFloat(item.price),
})),
total: parseFloat(order.total_price),
paymentMethod: order.payment_gateway,
}
}));
};
}
プリンター設定
印刷ペイロードの「printer」フィールドは以下を受け入れます。
| 値 | 説明 |
|---|---|
| "auto" | Print Agent設定で構成されたプリンターを使用 |
| "192.168.1.100" | IPでネットワークプリンターに直接接続 |
| "USB" | 最初に検出されたUSBプリンターを使用 |
エラー処理
ws.onmessage = (event) => {
const response = JSON.parse(event.data);
if (response.type === 'print_success') {
console.log('Printed successfully');
} else if (response.type === 'print_error') {
console.error('Print failed:', response.error);
// フォールバックUIを表示するか、リトライ
}
};
Print Agentがインストールされているかどうかの検出
UIに印刷機能を表示する前に、エージェントが実行中であるかを確認します。
async function isPrintAgentAvailable() {
return new Promise((resolve) => {
const ws = new WebSocket('ws://localhost:8765');
const timeout = setTimeout(() => {
ws.close();
resolve(false);
}, 1000);
ws.onopen = () => {
clearTimeout(timeout);
ws.close();
resolve(true);
};
ws.onerror = () => {
clearTimeout(timeout);
resolve(false);
};
});
}
// 使用法
const agentAvailable = await isPrintAgentAvailable();
if (!agentAvailable) {
// ダウンロードプロンプトを表示
window.open('/print-agent', '_blank');
}
Print Agentのダウンロード
MenuForma Print Agentは無料で、Mac、Windows、Linuxで利用可能です。USB、ネットワーク、Bluetoothのサーマルプリンターをサポートし、このガイドで説明されている完全なWebSocket APIを実装しています。
完全なAPIドキュメントとオープンソースコードについては、Print Agentページをご覧ください。
Related Articles
- 深刻な人手不足を救う!2025年、日本の飲食店が続々とQRコード注文を導入する理由
- 効率化か、雰囲気か?居酒屋におけるQRコード注文導入のジレンマと解決策
- インバウンド需要を取り込む!多言語対応QRコードメニューが日本の飲食店にもたらす恩恵