跳到主要內容
黯羽輕揚每天積累一點點

命令列二維碼

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

在提高生產力的路上,可能缺那麼一點想像力

寫在前面

發現一個有趣的東西,能在命令列顯示二維碼。日常一直是:

命令列起個 sync 服務
編輯器碼碼碼,瀏覽器看看看
...碼到差不多了
瀏覽器外掛程式生成個二維碼
掏出 100 個手機掃啊測啊
...咦,有問題
改改沒好,場景比較複雜,得抽出來定位
複製個 test 檔案
再生成個二維碼,再掃再測,o 了
...額,又發現個問題
...

瀏覽器二維碼外掛程式差不多能滿足需求,在 IDE、瀏覽器、終端機、Finder 之間頻繁切換,雖然有點麻煩,但沒有發現更好的辦法……直到看見命令列二維碼,怎麼可以這麼機智

一.原理

看到「命令列二維碼」,想也知道原理是什麼:輸出到螢幕時可以控制前景色、背景色、文字樣式

要輸出二維碼,只要能改背景色就夠了,用白空格黑空格就能拼出來

例如:

# 輸出 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
    # 左移一格,輸出字元
    echo -en "\033[1D$c"
done

二.具體實作

1. 生成二維碼元數據

根據輸入的字串,按照二維碼規則計算出二值矩陣

這個過程手動實作起來比較費勁,因為二維碼是一個有幾百項專利的技術,見 http://www.qrcode.com/en/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

但還是有必要了解一些概念:

  • 尺寸(spec 裡叫 Version ,上面的開源版實作裡叫 TypeNumber

    值為 1401 對應最小矩陣 21x2140 對應最大的 177x177

  • 定位圖案

    最明顯的是二維碼角角的 3 個回形框,3 個點確定一個矩形。其他位置也有用來定位的圖案

  • 糾錯級別

    'L', 'M', 'Q', 'H' 4 個糾錯級別,級別越高,容錯率越高,攜帶的糾錯數據也越多,所以才有個性化二維碼

  • 資料類型

    保留數據(格式資訊,版本資訊,定位圖案資訊),實際數據資訊和糾錯數據

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);

然後就能在命令列顯示一個大大的二維碼了,如圖:

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

3. 命令列優化

但是,在命令列顯示的話,尺寸太大

二維碼最小尺寸也是 21x21 ,黑框裡 21 行幾乎佔滿預設一屏了,碼稍長一點就顯示不全了,而一般 url 碼都超過 21 行,例如:

// 在糾錯級別為 M(預設)時
// 21 行的二維碼只能顯示 14 個字元
https://www.ay
// 22 行的只能顯示 26 個字元
https://www.ayqy.net/blog/
//...

所以要設法讓輸出的二維碼行列尺寸小一點,最容易想到的就是用奇怪的 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]

雖然醜一點,但仍然是可用的。那麼還能不能更小,如果想縮小兩倍呢?

用同樣的方法做不到,因為 Unicode 字���只有「下四分之一方塊」、「下四分之三方塊」和「左四分之三方塊」、「左四分之一方塊」,不夠用了

三. 開源 npm 套件

很巧的是,上面提到的所有事情都有人做了: qrcode-terminal-alpha

把命令列二維碼添進工作流程工具裡,建置完畢直接顯示二維碼,掃碼會方便不少

參考資料

評論

暫無評論,快來發表你的看法吧

提交評論