寫在前面
發現一個有趣的東西,能在命令列顯示二維碼。日常一直是:
命令列起個 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)值為
1到40,1對應最小矩陣21x21,40對應最大的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[/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[/caption]
再把列空格數量減半,這樣寬高尺寸就都能縮小一半,如圖:
[caption id="attachment_1326" align="alignnone" width="768"]
terminal-qrcode-small[/caption]
雖然醜一點,但仍然是可用的。那麼還能不能更小,如果想縮小兩倍呢?
用同樣的方法做不到,因為 Unicode 字���只有「下四分之一方塊」、「下四分之三方塊」和「左四分之三方塊」、「左四分之一方塊」,不夠用了
三. 開源 npm 套件
很巧的是,上面提到的所有事情都有人做了: qrcode-terminal-alpha
把命令列二維碼添進工作流程工具裡,建置完畢直接顯示二維碼,掃碼會方便不少
參考資料
-
QR Code Generator :線上二維碼生成器
-
kazuhikoarase/qrcode-generator :js api
暫無評論,快來發表你的看法吧