5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Ruby] rqrcodeで連結QRコードを生成する(知識編)

Last updated at Posted at 2020-08-25

連結QRコードとは?

  • QRコードには長いデータを最大16個のQRコードに分割して、読み取りの際に結合する「連結機能」が存在します。(詳しくは、QRコードドットコム 参照)
  • 日本においては、病院/クリニックから貰う処方箋で見かける機会が多いと思います。
  • サードパーティ系の帳票出力ライブラリなどでは出力機能がサポートされていたりするのですが、なかなかOSSのライブラリでは見つからないので、従来から使っていた rqrcode を改造して出力できるようにしてみました。
    • 今回は、上記の「処方箋」に記録する連結QRコードを出力することをターゲットとしているので、 8bit_byte モードのQRコードだけを対象にしています。

どうすれば連結QRコードになる?

  • 通常のQRコードの場合、書き込むデータのヘッダ部分は、以下のような構成になります。

    • 尚、QRコードには、1〜40というバージョン(=QRコードの大きさ)があり、これにより1つのQRコードに記録できるデータサイズが変わります。(こちらを参照)
    • QRコードに対するバージョンの指定は、ヘッダ部分とは異なるところに書き込むらしく、ここでは割愛します。
    • SS の長さは、QRコードのバージョンとエンコーディングモードに応じて8〜16bitの間で可変です。
- 長さ 記録する内容
E 4bit エンコーディングモード(下表参照)
SS (可変) QRコードに記録するデータの長さを記録
エンコーディングモード モードを表す値
numeric 1 (0b0001)
alpha_numeric 2 (0b0010)
8bit_byte 4 (0b0100)
  • 8bit_byte モードの連結QRコードの場合は、ヘッダ部分を以下のように記録します。
    • こちらを参考にさせて頂きました。
- 長さ 記録する内容
3 4bit 連結QRコードを示すモード(0b0011)
N 4bit 連結するQRコードの順序番号(0〜15の連番)
T 4bit QRコードの最後の順序番号(0〜15の連番)
PP 8bit 全てのデータのパリティ値(全てのbyteのXOR値)
E 4bit エンコーディングモード(8bit_byte = 4)
SS (可変) 1つのQRコードに記録するデータの長さを記録
  • ということで、連結QRコードを出すには以下のような手順になります。

    • 連結QRコードのバージョン(大きさ)を決める。
      • 連結は最大で16個です。
      • また、連結QRコードだと、通常のQRコードより記録できるデータ量が2byte少なくなるようです。(データ量は20bit増えていると思うのですが・・何故か -2byteまで記録出来るようです)
      • 上記2点も加味して、バージョンを決める必要があります。
      • 通常全てのQRコードは、同じバージョン(大きさ)で作ります。(バージョンがバラバラなQRコードを連結できるかは試したことがありませんが、読めないリーダーもありそうなので避けたほうが無難です)
    • QRコードに収めるデータからパリティを計算する。(全てのbyteのXOR値=8bit)
    • QRコードに収めるデータを、1つのQRコードに収まるように分割する。(各QRコードのキャパシティ - 2byte で収まるようにする)
    • 必要な数のQRコードを生成して、それぞれレンダリングする。
      • 全てのQRコードに、同じ「パリティ値」と「最後の順序番号」を指定します。
      • 「順序番号」と格納するデータは、QRコードごとに指定します。
  • 実際に rqrcode を改変しての連結QRコードの出力は 実践編 で解説します。

リーダーごとに挙動が違うので注意しましょう

  • 薬局などの業務では、レーザー式のバーコードスキャナーなどが利用されています。これらは結構高価なので、動作検証用に機器を揃えるのは少々ハードルが高いです。(私は個人的にも興味があったので、ヤフオクで中古品を安価にGETしました。意外と頻繁に出品されているようです。)

  • なので、バーコードスキャナを使った最終確認までの間は、連結QRコード読み取りに対応したスマホアプリを使って動作確認をしていました。(iOSアプリだと、私は3種類しか見つけていません)

  • しかし、リーダーアプリもバーコードスキャナーも、製品によって結構挙動が違ったりします。

    • パリティ値が合っているかを確認していないものがありそうました。(実運用上は大した問題ではありませんが)
    • 連結QRコードの指定なのにQRコードが1つしかない(分割されていない)場合に、読み取れないものがありそうました。(データ量が少ない場合は、通常のQRコードで出力したほうが良さそうです)
    • 漢字(ShiftJIS)の上位バイトと下位バイトが、2つのQRコードに跨ってしまった場合に文字化けを起こすものがある。(アプリにこの挙動がよく見られます)
  • 上記のことから、特に業務利用の場合は、実際に利用される機器などを想定して動作確認環境を揃えたほうが無難ですね。

    • バーコードスキャナなら、少し古めの機種も含めて、何種類か用意したほうが良いかも知れません。

色々読み取りテストしてみた

  • ちょっと変な状態の連結QRコードを色々作って、4種類のリーダーで試してみました。

    • スキャナーA → 某有名メーカのレーザー式のハンディスキャナー。但しかなり古い機種。(Win98もサポート)
    • アプリB → 連結QRコードが読める某アプリで、スキャナーAのメーカが出している
    • アプリC → 連結QRコードが読める某アプリ
    • アプリD → 連結QRコードが読める某アプリ
    • アプリは全て2020/08/29現在のバージョンでの検証結果です。
QRコードの状態 スキャナーA アプリB アプリC アプリD 補足
連結だが1枚で収まっている 反応しない 反応しない OK OK ※1
最後の1枚が制御コードだけ OK OK 解析エラー OK CR/LF/EOFだけ格納
2バイト文字が2つに跨っている OK OK 解析エラー 文字化け
パリティ値間違え(全て) 読取完了しない※2 読取完了しない※2 解析に問題発生 OK 全て同じパリティ値を指定
1枚だけパリティ値間違え 読取完了しない※2 読取完了しない※2 異なるQRコード 異なるQRコード
サイズが揃っていない OK OK OK OK
  • ※1:ちなみに、同じメーカーの最近の機種では読み取れるらしいです。
  • ※2:1枚ごと反応はしますが、全てのコードを読んでも読み取り完了になりません。
  • 考察と感想
    • 2バイト文字(漢字など)による文字化けや解析エラーは、実運用ではちょっと致命的ですよね。(流石に業務用のスキャナーには、そんなバグは無いと思いますが)
    • 1枚に収まる場合は、連結じゃなく通常のQRコードで出力したほうが無難なようです。
    • パリティについては、「ちゃんとVerifyしている」ものと「同じ連結QRコードかどうかのチェックにだけ使っている」ものがあるようですね。(正しい値を設定しましょう)
    • スキャナーAとアプリBは同じメーカなだけあって、流石に挙動が似ていますね。

参考文献

この記事は以下の情報を参考にして執筆しました。

更新履歴

  • 2020.08.29 「色々読み取りテストしてみた」を追加しました。(バーコードスキャナを手に入れたので)
5
5
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
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?