メインコンテンツへ移動

コマンドラインQRコード

無料2017-02-05#Tool#终端输出二维码#命令行显示二维码#terminal qrcode#二维码生成算法#qrcode spec

生産性を向上させる道のりにおいて、欠けているのは少しの想像力かもしれません

はじめに

面白いものを見つけました。コマンドラインでQRコードを表示できるものです。これまではずっと:

コマンドラインでsyncサービスを起動
エディタでコードを書き、ブラウザで確認
...ある程度書けたら
ブラウザのプラグインでQRコードを生成
スマホを100台取り出してスキャンしてテスト
...あれ、問題がある
修正してもうまくいかない。シーンが複雑なので、切り出して原因を特定する必要がある
テスト用ファイルをコピー
再度QRコードを生成し、スキャンしてテスト。よし完了
...おっと、また別の問題が見つかった
...

ブラウザのQRコードプラグインで要件はほぼ満たせますが、IDE、ブラウザ、ターミナル、Finderの間を頻繁に行き来するのは少し面倒です。しかし、より良い方法が見つからず……。コマンドラインQRコードを見るまでは。なんて賢いんでしょう。

1. 原理

「コマンドラインQRコード」と聞いて、原理は想像がつきます。画面に出力する際に、前景色、背景色、テキストスタイルを制御できることを利用しています。

QRコードを出力するには、背景色を変更できれば十分です。白いスペースと黒いスペースを組み合わせることで作ることができます。

例えば:

# focus here と出力
# focus は黒背景に白文字、スペースはデフォルト、here は青背景に白文字で太字
echo "\e[40;0;37mfocus\e[0m \e[44;1;37mhere\e[0m"

\e[0m はデフォルトスタイルにリセットします。一般的な制御シーケンスの形式は:

# \e[ で始まり、m で終わる
# セミコロンで区切られた3つの値は、それぞれ背景色、テキストスタイル、前景色
\e[40;0;37m

サポートされている値は以下の通りです:

# テキストスタイル
0: 標準テキスト
1: 太字
4: 下線

# 前景色 30-37
30: 黒
31: 赤
32: 緑
33: 黄
34: 青
35: 紫
36: シアン
37: 白

# 背景色 40-47
40: 黒
41: 赤
42: 緑
43: 黄
44: 青
45: 紫
46: シアン
47: 白

さらにより強力なものもあり、カーソルの移動、特定の行の削除、画面のクリアなどがあります。例えば、文字によるプログレスインジケーター:

echo -n '-'
arr=('\\' '|' '/' '-' '|' '100%')
for c in ${arr[@]};
do
    # 1秒待機
    sleep 1
    # 左に1つ戻り、文字を出力
    echo -en "\033[1D$c"
done

2. 具体的な実装

1. QRコードメタデータの生成

入力された文字列に基づき、QRコードの規則に従って2値行列を計算します。

このプロセスを自力で実装するのはかなり骨が折れます。なぜならQRコードは数百もの特許を持つ技術だからです。詳細は http://www.qrcode.com/jp/patent.html を参照。ISO Specification を購入(または入手)して実装する必要があります:

Obtaining QR Code Specification

QR Code is established as an ISO (ISO/IEC18004) standard. QR Code specification can, therefore, be purchased from this organization.

Purchasing ISO Standards

Please search by inputting ISO No.18004 or X0510 to "Search and ISO Catalogue". http://www.iso.ch/iso/en/prods-services/ISOstore/store.html

しかし、オープンソース版があり、様々な言語で実装されています:https://github.com/kazuhikoarase/qrcode-generator

それでも、いくつかの概念を知っておく必要があります:

  • サイズ(仕様書では Version、上記のオープンソース実装では TypeNumber と呼ばれます)

    値は 1 から 40 で、1 は最小の 21x21 行列、40 は最大の 177x177 に対応します。

  • 位置検出パターン(ファインダパターン)

    最も目立つのは、QRコードの四隅のうち3つにある回し車のような四角い枠です。3つの点で1つの矩形を確定します。他の場所にも位置決めのためのパターンがあります。

  • 誤り訂正レベル

    'L', 'M', 'Q', 'H' の4つのレベルがあります。レベルが高いほど、より多くの汚れや欠損に耐えられますが、その分誤り訂正データが増えます。これにより、デザイン性の高いQRコードなども可能になります。

  • データタイプ

    予約データ(形式情報、バージョン情報、位置検出パターン情報)、実際のデータ情報、および誤り訂正データ。

2. 出力

前述の qrcode-generator の主な JS API は以下の通りです:

// インスタンス作成
qrcode(typeNumber, errorCorrectionLevel) => QRCode
// エンコードする文字列を渡す
addData(data, mode) => void

// 行列を計算
make() => void

// 結果行列の行列数(列数=行数)を取得
getModuleCount() => number
// 行列のセルの値を取得
isDark(row, col) => boolean

メタデータができたら、行列をトラバースして黒白のスペース文字列を連結し、出力します:

// 黒白のスペース
var black = "\033[40m  \033[0m",
    white = "\033[47m  \033[0m",
    toCell = function (isBlack) {
        return isBlack ? black : white;
    },
    repeat = function (color) {
        return {
            times: function (count) {
                return new Array(count).join(color);
            }
        };
    },
    fill = function(length, value) {
        var arr = new Array(length);
        for (var i = 0; i < length; i++) {
            arr[i] = value;
        }
        return arr;
    };

//...インスタンス作成と行列計算部分は省略

// トラバース
var border = repeat(white).times(qrcode.getModuleCount() + 3);
output += border + '\n';
qrcode.modules.forEach(function (row) {
    output += white;
    output += row.map(toCell).join(''); 
    output += white + '\n';
});
output += border;

// 出力
console.log(output);

これで、コマンドラインに大きなQRコードが表示されます。以下の図のようになります:

[caption id="attachment_1323" align="alignnone" width="625"]terminal-qrcode terminal-qrcode[/caption]

3. コマンドライン向けの最適化

しかし、コマンドラインで表示すると、サイズが大きすぎます

QRコードの最小サイズでも 21x21 で、黒い枠の中に 21 行あるとデフォルトの画面1枚をほぼ占有してしまいます。少し長いコードになると全体が表示されなくなりますが、一般的な URL は 21 行を超えます。例えば:

// 誤り訂正レベルが M(デフォルト)の場合
// 21行のQRコードは14文字までしか表示できません
https://www.ay
// 22行の場合は26文字まで表示できます
https://www.ayqy.net/blog/
//...

そこで、出力するQRコードの縦横サイズを小さくする方法を考える必要があります。最も簡単なのは、特殊な Unicode 文字を使って組み立てることです:

[caption id="attachment_1325" align="alignnone" width="484"]unicode-block unicode-block[/caption]

さらに列のスペース数を半分に減らせば、幅と高さの両方を半分に縮小できます。以下のようになります:

[caption id="attachment_1326" align="alignnone" width="768"]terminal-qrcode-small terminal-qrcode-small[/caption]

少し見た目は悪いですが、十分に使えます。では、もっと小さく、例えばさらに半分(合計4分の1)に縮小することはできるでしょうか?

同じ方法では不可能です。なぜなら Unicode 文字には「下4分の1ブロック」、「下4分の3ブロック」、「左4分の3ブロック」、「左4分の1ブロック」などは存在せず、足りないからです。

3. オープンソース npm パッケージ

幸運なことに、前述したすべてのことをすでに行っている人がいます:qrcode-terminal-alpha

コマンドラインQRコードをワークフローツールに追加すれば、ビルド完了後に直接QRコードが表示され、スキャンが非常に便利になります。

参考資料

コメント

コメントはまだありません

コメントを書く