ブラウザからのESC/POS印刷:開発者向けガイド

ブラウザでの印刷の問題

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

流れはシンプルです。

  1. Webアプリがws://localhost:8765へのWebSocket接続を開きます。
  2. レシートを記述したJSONペイロードを送信します。
  3. Print AgentがそれをESC/POSに変換し、プリンターに送信します。
  4. プリンターはサイレントに印刷します — ダイアログもドライバー操作もありません。

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

MenuForma Products