小程序二维码中如何使用二进制模式

背景

最近在为我们的公交小程序添加二维码功能,挺简单的需求对吧?我整了好两天了,我原本以为一个二维码能有什么复杂的,文本是什么内容,扫出来是什么内容就完了。没有想到公司用的是二进制模式下二维码,我翻阅了 github 上现在小程序中专门做二维码的库,发现没有实现这个功能的,后来就改采取了一种中转的模式。

实现

我现在的二维码数据如下:

1
1601712401010000021236110001053001003604040021A56C9825FB4F2054863A26DD3E79D564898D195445AB2D5C4B8B958FD2AD7241100960FD0B466C114D26C09FA483A4F91CB6179ABFD356FA4C33AE1D559C13271863E40D69012085E2AC2214C58DEC620488D52D79DCD0074FE4CBEBAC97684E1832303230303432383337323038333230100000000000000000009999999999999999E60000C807162E89093B3470EAE9EE2356B753C141BA020FED9887A4BB09E1EAE24BA4AB635EEB2CC83A8028010108333730383030303131011A535A4D30303030347C313132323333343435357C307C34387C3115DAF7B74C78BD8B6D6925F25FE51BD2DC9F4594F457E94C1AFFCF5C85B4A3A2DF9495FA42FADA91024BD3F4CCE7DFC094BCD9B08B146DC563DC5B752D90E6D2525EE7397E15C00FCA915CA52E5170F884AABD2002DB2E08B027D07BDA454115E0F6790F37D4D218F82230FFDF1E43A67EA698D9D34E4605FB83F9430034ED3FC142A9A11C8B

我在 web 端下发现在 node-qrcode这个库可以很轻松的输入二进制的二维码,但是这个库在小程序端现在跑不起来, 主要是不支持Buffer

1
2
3
4
5
6
7
8
9
// Regular array example
// WARNING: Element values will be clamped to 0-255 even if your data contains higher values.
const QRCode = require('qrcode')
QRCode.toFile(
'foo.png',
[{ data: [253,254,255], mode: 'byte' }], // mode为二进制模式
...options...,
...callback...
)

我们一般成二维码会用到canvas或者svg格式,然后我们知道小程序里其实是可以用 base64 化的 svg 做为图片的 src, 如:

1
<image src='data:image/svg+xml;base64,...'/>

所以我只能另找一个可以转成 svg 并且支持二进制模式的库就好了。但是很可惜,我没有找到,但是这个库qrcode-generator却有方法 可以添加数据处理, 我尝试将我的数据这个方法转为 binary 后终于成功了, 下面是具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import QRCode from "qrcode-generator";

function hexToBytes(hex: string) {
const bytes = [];
for (let c = 0; c < hex.length; c += 2) {
bytes.push(parseInt(hex.substr(c, 2), 16));
}
return bytes;
}

const genQRcordBinImg = (data: string) => {
QRCode.stringToBytes = hexToBytes;
const typeNumber = 0; // 0 is auto
const errorCorrectionLevel = "L";
const qr = QRCode(typeNumber, errorCorrectionLevel);
qr.addData(data, "Byte");
qr.make();
const rst = qr.createSvgTag(2, 0);
return `data:image/svg+xml;base64,${btoa(rst)}`;
};

const qrCodeImg = genQRcordBinImg(
"1601712401010000021236110001053001003604040021A56C9825FB4F2054863A26DD3E79D564898D195445AB2D5C4B8B958FD2AD7241100960FD0B466C114D26C09FA483A4F91CB6179ABFD356FA4C33AE1D559C13271863E40D69012085E2AC2214C58DEC620488D52D79DCD0074FE4CBEBAC97684E1832303230303432383337323038333230100000000000000000009999999999999999E60000C807162E89093B3470EAE9EE2356B753C141BA020FED9887A4BB09E1EAE24BA4AB635EEB2CC83A8028010108333730383030303131011A535A4D30303030347C313132323333343435357C307C34387C3115DAF7B74C78BD8B6D6925F25FE51BD2DC9F4594F457E94C1AFFCF5C85B4A3A2DF9495FA42FADA91024BD3F4CCE7DFC094BCD9B08B146DC563DC5B752D90E6D2525EE7397E15C00FCA915CA52E5170F884AABD2002DB2E08B027D07BDA454115E0F6790F37D4D218F82230FFDF1E43A67EA698D9D34E4605FB83F9430034ED3FC142A9A11C8B"
);
1
<image :src="qrCodeImg" />