LoginSignup
5
0

Phomemo M02SにWeb Serial APIで画像を印刷する

Last updated at Posted at 2023-12-02

この記事について

この記事は SUPER STUDIO Advent Calendar 2023 の3日目の記事になります。

Phomemo M02Sとは

Phomemo M02S は中国メーカー製の「スマホ対応モバイルラベルプリンター」になります。
エアメールのデザインをしたおもちゃみたいな見た目ですが、300DPIのサーマルプリンターを小さなユニットにまとめあげていて、Amazon等で7000円くらいで売っています(2023年12月現在)。
スマホアプリ(iOS/Android)とBluetoothで接続することでアプリ側で指定した画像などを印刷することができます。

PCから印刷しよう

純正アプリはスマホのみで、PC用のアプリやドライバーなどは公式から提供されていません。
けれども、先人たちはいろいろと試行錯誤して印刷を実現しています。

@cure_honey さんの記事
コマンドの解析結果など、とても参考になりました。

Stargirl Flowersさんのリポジトリ
こちらはPythonでの出力プログラム。ラスターデータの送り方など参考にさせてもらいました。

自分はブラウザ(HTML+JavaScript)からの出力にチャレンジしてみました。

Web Serial API

最初、Bluetooth接続ということでWeb Bluetooth APIを試してみましたが、結局はBT経由のシリアル通信ということでWeb Serial APIから出力するのが正解でした。
なお、Web Serial APIは、PCのChrome、Edge、Operaしかサポートされていません

    const ESC = 0x1B;
    
    port = await navigator.serial.requestPort();
    await port.open({ baudRate: 115200 });

    writer = port.writable.getWriter();

    await writer.write(new Uint8Array([ESC, 0x40, 0x02])); // reset

serial.requestPort() をコールするとブラウザがシリアル通信ポートを聞いてきます。
自分の環境の場合は以下のようになりました。

Windowsの場合

スクリーンショット 2023-11-04 235243.jpg
設定→Bluetoothとデバイス→プリンターとスキャナーからM02Sを追加します。
「ドライバーは使用できません」と表示されますが無視して構いません。
この状態で上記プログラムを実行すると、シリアルポートへの接続先一覧が表示されるので「M02S」を選択すれば接続は完了です。
スクリーンショット 2023-11-05 195934.png

Macの場合

スクリーンショット 2023-11-05 21.22.13.jpg
設定アプリのBluetoothからM02Sを追加します。
「接続済み」と表示されたあとすぐ「未接続」になりますが問題ありません。逆に接続をしてしまうとプログラムから制御できなくなります。
この状態で上記プログラムを実行すると、シリアルポートへの接続先一覧が表示されるので「cu.M02S」を選択すれば接続は完了です。
スクリーンショット 2023-11-05 21.23.25.png

画像のラスターデータ化

Phomemo M02Sは熱転写式の黒印刷のみなので、画像を印刷しようとするなら白黒2値の画像データに変換しないとモノクロ印刷できません。
そこでカラー画像 → グレイスケール画像 → 誤差拡散法によるハーフトーン処理を施す必要があります。
Pythonとかだとこの辺の画像処理のライブラリはすぐ見つかりますが、それらしいJavaScriptの画像処理ライブラリが見つかりませんでした。
ここでも先人の知恵を借りました。
@ltzz さんが書いたドンピシャの記事とサンプルソースがありましたので、そのまま移植させてもらいました。

これでCanvasに表示できるRGBAの4バイトのピクセルデータが出来上がるので、R/G/Bチャンネルのどれも黒は0x00、白は0xFFになります。
これを白黒2値のラスターデータにするために、Rのチャンネルが0xFFならビットデータは「0」(白は印字しないので0になる)、0x00ならビットデータは「1」としてビット列をバイトデータに変換します。

  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x += 8) { // 8bitを1Byteにするため8単位
      let bit8 = 0;
      for (let i = 0; i < 8; i++) {
        let r = inputData[((x + i) + y * width) * 4]; // Rチャンネルのデータを取り出す
        bit8 |= (r & 0x01) << (7-i); // 1Byteに詰めていく
      }
      outputArray[bytes] = ~bit8; // ビット反転(白は0になるため)
      bytes++;
    }
  }

成果物

デモ

[ファイルを選択]ボタンを押してローカルの画像ファイルを選択すると、Phomemo M02Sの解像度に合わせて横576ピクセルにリサイズして画像表示します。
画像選択後、[印刷]ボタンを押すと、シリアルポートの選択になるのでM02Sを選択すれば印刷されます。
スクリーンショット 2023-11-05 202158.png

おまけ

なかなか思うように画像が出力されなくて、試行錯誤してデバッグしてる様子。
業務ではバックエンドでクラウドを触っているので忘れていましたが、この機器と対話しながら仕様を理解していく感覚は制御系プログラミングならではですね。
スクリーンショット 2023-11-05 203159.png

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