LoginSignup
1
2

Web アプリから Bluetooth で印刷する

Last updated at Posted at 2024-04-14

Receipt.js

Web Serial API でレシートプリンター (サーマルプリンター) が動きます。
https://github.com/receiptline/receiptjs

印刷データはレシートマークダウン。難しいコマンド制御は不要です。
https://marketplace.visualstudio.com/items?itemName=receiptline.receipt-markdown

レシートプリンター

ユーザーの操作

「つなぐ・ひらく・えらぶ」の 3 ステップ。

Bluetooth でつなぐ

つなぐ
レシートプリンターをペアリングします。

Web ページを開く

ひらく
PC 版 Chrome (Edge, Opera) に対応。

プリンターを選ぶ

えらぶ
プリンター (シリアルポート) を選んで印刷します。

印刷機能の追加

Web アプリ (Web サイト) への追加も簡単。

印刷データを作る

エディタ
Receipt.js Designer または VS Code 拡張機能 で編集します。

HTML に組み込む

<script type="text/javascript" src="script/receipt.js"></script>
<script type="text/javascript" src="script/receipt-printer.js"></script>
<script type="text/javascript" src="script/receipt-serial.js"></script>
<script type="text/javascript" src="script/qrcode-generator/qrcode.js"></script>

ライブラリ本体と、オプションのコマンド変換、シリアル通信、二次元コードです。

スクリプトを追加する

document.querySelector('button').onclick = () => {
    const markdown = `
    ^^電子チケット控え
    -
    紛失しないよう十分ご注意ください

    {code:NPCCMLIN20230723180001123901;option:qrcode,8,h}

    1階  12列  39番
    `;
    const conn = ReceiptSerial.connect();
    conn.on('ready', async () => {
        await conn.print(markdown);
        conn.close();
    });
};

数行の JavaScript で接続して、印刷して、切断。

例のインスタントカメラ

過去記事「簡単レシート印刷 receiptline と 20 行の JavaScript でレジプリンターをインスタントカメラにしてみた」のコードを修正。

Chromebook で実行

インスタントカメラ
Chromebook のブラウザだけで完結。Node.js は不要です。

撮影&プリント

撮影とプリント
画像をタップして撮影・プリント。接続されていない場合はポートを選択します。

ソースコード

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Instant Camera</title>
    <script type="text/javascript" src="script/receipt.js"></script>
    <script type="text/javascript" src="script/receipt-printer.js"></script>
    <script type="text/javascript" src="script/receipt-serial.js"></script>
    <!--<script type="text/javascript" src="script/qrcode-generator/qrcode.js"></script>-->
    <script type="text/javascript">
        async function initialize() {
            const video = document.querySelector('video');
            const canvas = document.querySelector('canvas');
            let conn = null;
            // video
            video.srcObject = await navigator.mediaDevices.getUserMedia({ audio: false, video: true });
            video.onloadedmetadata = event => {
                canvas.height = Math.trunc(canvas.width * video.videoHeight / video.videoWidth);
            };
            video.onclick = event => {
                // image
                canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
                let data = `{i:${canvas.toDataURL('image/png').slice(22)}}\n`;
                // date
                const now = new Date();
                data += `${new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString()}|`;
                // print
                if (conn) {
                    conn.print(data, '-g 1.8');
                }
                else {
                    conn = ReceiptSerial.connect();
                    const timeout = setTimeout(conn.close, 15000);
                    conn.on('disconnect', () => {
                        conn = null;
                    });
                    conn.on('ready', () => {
                        clearTimeout(timeout);
                        conn.print(data, '-g 1.8');
                    });
                }
            };
        }
    </script>
</head>
<body onload="initialize()">
    <video autoplay style="width: 100%;"></video>
    <canvas width="576" height="432" style="display: none;"></canvas>
</body>
</html>

以上です。ではまた!

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2