写在前面
发现一个有趣的东西,能在命令行显示二维码。日常一直是:
命令行起个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);
然后就能在命令行显示一个大大的二维码了,如图:
3.命令行优化
但是,在命令行显示的话,尺寸太大
二维码最小尺寸也是21x21
,黑框里21
行几乎占满默认一屏了,码稍长一点就显示不全了,而一般url码都超过21
行,例如:
// 在纠错级别为M(默认)时
// 21行的二维码只能显示14个字符
https://www.ay
// 22行的只能显示26个字符
https://www.ayqy.net/blog/
//...
所以要想办法让输出的二维码行列尺寸小一点,最容易想到的就是用奇怪的Unicode
字符拼:
再把列空格数量减半,这样宽高尺寸就都能缩小一半,如图:
虽然丑一点,但仍然是可用的。那么还能不能更小,如果想缩小两半呢?
用同样的方法做不到,因为Unicode
字符只有“下四分之一方块”、“下四分之三方块”和“左四分之三方块”、“左四分之一方块”,不够用了
三.开源npm包
很巧的是,上面提到的所有事情都有人做了:qrcode-terminal-alpha
把命令行二维码添进工作流工具里,构建完毕直接显示二维码,扫码会方便不少
参考资料
QR Code Generator:在线二维码生成器