ブラウザからPhomemo M02Sをレシートプリンターにする

## この記事について
この記事は [SUPER STUDIO Advent Calendar 2023](https://qiita.com/advent-calendar/2023/superstudio) の4日目の記事になります。
また、[前回の記事](https://qiita.com/tana_p/private/33b8a8e9f247e406afa2)からの続きとなります。

## なぜレシート印刷なのか
自分の所属する株式会社SUPER STUDIOでは、統合コマースプラットフォームの『ecforce』を運営しており、約1200ショップ以上のEC事業社さまにご導入いただいております(2023年11月時点)。
昨今のEC業界では、ECサイト（オンライン）と実店舗（オフライン）を融合した顧客体験の向上を目指した「OMO(Online Merges with Offline)」が注目されていて、弊社でも[リアル店舗の出店](https://www.super-studio.jp/news/20230707)を行っています。
そこでリアル店舗ではレシートを印刷してお客様に手渡すことが必要になるだろうと思ったのがきっかけです。

## レシートプリンター
いわゆる業務用のレシートプリンターは5万円くらいはするもので、技術検証用に個人で買うには少しお高い感じです。
またよくある業務用のレシートプリンターはESC/POSコマンドに準拠しており、各メーカー謹製のSDKキットを使って開発をしたり、OSSの[ReceiptLine](https://qiita.com/yamukotonaku/items/53f3fa167ca7c867c4b4)を使ったりするのが一般的だと思います(スター精密社製だとStarPRNTコマンドですね)。
ESC/POSコマンドは印字する文字は普通に文字データを送信します。そのため一般的な業務用のレシートプリンターは文字フォントデータを内蔵しています。日本語の出力をするには日本語文字フォントが必要で、そのため日本で使われる業務用レシートプリンターはほぼ日本製です。
前回の記事で使ったPhomemo M02Sは、ESC/POSコマンドに部分的に対応はしているものの文字フォントは内蔵されていないらしく、そのためラスターデータでの画像印刷しかできないようです。
一般的なレシート印刷とはだいぶかけ離れた構成とはなりますが、ECシステムでのレシート印刷を想定してサンプルを作ってみました。

## レシートデータ
ECシステムが印刷データを作ってもプレビューするのが難しいことを考えると、いっそHTMLで普通にレシートのイメージを表現してみます。
印刷することを考えて、HTML上で横幅576ピクセル(Phomemo M02Sの印刷解像度)に合わせてあります。

CSS
```css
    .recipt{
      width: 576px;
      background-color: #FFFFFF;
      font-size: x-large;
    }
    .border{
      padding: 5px 10px 0px 10px;
    }
    .item{
      width: 65%;
    }
    .price{
      width: 35%;
      text-align: right;
    }
    .list{
      display: flex;
    }
```
HTML
```html
      <div id="src" class="recipt">
        <div class="border">
          <p style="text-align: center;">
            <img src="logo.png" alt="ロゴ" />
          </p>
          <p style="text-align: center;">
            TEL (03)-9999-9999
          </p>
          <p>
            <h2 style="text-align: center;">領収証</h2>
          </p>
          <p>
            2023年12月15日(金) 14:23 注文番号 12345678
          </p>
          <p>
            <div class="list">
              <div class="item">いちご</div>
              <div class="price">1点  ¥ 300</div>
            </div>
            <div class="list">
              <div class="item">ぶどう</div>
              <div class="price">1点  ¥ 500</div>
            </div>
            <div class="list">
              <div class="item">メロン</div>
              <div class="price">1点  ¥ 2,500</div>
            </div>
          </p>
          <hr>
          <p>
            <div class="list">
              <div class="item">小計</div>
              <div class="price">¥ 3,300</div>
            </div>
            <div class="list">
              <div class="item">消費税等</div>
              <div class="price">¥ 330</div>
            </div>
            <div class="list">
              <div class="item" style="font-size: xx-large;">合計</div>
              <div class="price" style="font-size: xx-large;">¥ 3,630</div>
            </div>
          </p>
          <hr>
          <p style="text-align: center;">
            <span style="font-size: medium;">注文詳細は以下のQRコードから</span><br/>
            <img src="qrcode.png" alt="QRコード" />
          </p>
          <hr style="border-top: 2px dashed; border-right: none; border-bottom: none; border-left: none;">
        </div>
      </div>
```
こんな感じです。
![スクリーンショット 2023-11-06 011223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19193/960266cc-f41d-4996-93c6-d9d34b0c9388.png)

## HTMLを画像に変換
前回、画像を印刷する部分を作ったので、HTML要素を画像に変換できればあとは印刷するだけです。
わりとその用途でやり方は何種類かあるのですが、今回は一番簡単に導入できそうな[html2canvas](https://html2canvas.hertzen.com/)を使用してみました。
Canvasへの画像変換は簡単に行えましたが、HTMLのピクセル指定よりも想定外に大きい画像データになってしまい、印刷したときに1枚に収まりきりませんでした。
これはオプションで元画像の `width` と `height` 、それと `scale: 1`を指定することで解決できました。

```javascript
  let src = document.querySelector("#src");
  html2canvas(src, {
    width: src.width,
    height: src.height,
    scale: 1
  }).then(canvas => {
    document.querySelector("#print_src").appendChild(canvas);
    print(document.querySelector("canvas")); // 印刷処理
  });
};

```

なお、HTMLソースを画像に変換する過程でCORS制限に引っかかるようになったので、動作確認にはサーバーを立ててHTMLを配置する必要があります。

これでCanvasにレシート画像が作成できたので、あとは前回の記事の画像をPhomemo M02Sに印刷する処理をそのまま流用できました。

## 成果物

https://github.com/tanapi/m02s_receipt_print

[デモ](https://tanapi.github.io/m02s_receipt_print/)

ロール紙に印刷してみると、思ったよりはレシートっぽく見えるなという感想です。
![スクリーンショット 2023-11-06 015044.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19193/4d4c8e56-ed00-e2f8-19da-5b0bbabb1281.png)