【CSDN 编者按】 近年来,Rust 成为了诸多企业眼中的“香饽饽”,无论是微软、亚马逊、Google 等大厂,还是 Linux 这样的主流项目,都在深度拥抱 Rust。那么,对于普通开发者而言,该如何上手 Rust?在本篇文章中,15 岁的开发者 通过制作一个二维码编码器的项目来学习 Rust 编程语言, 也希望对你有所启 发。
(资料图)
原文链接:/blog/qr-code-generator-in-rust/
未经允许,禁止转载!
大家好,我想向大家介绍一下我是如何从零开始学习 Rust 编程的,为此我选择了制作 QR 码编码器这个目标,并得到了 Pionir 免费学校一位导师的帮助。
至于我为什么会选择 Rust?
首先,我想尝试一些新的东西,我以前使用简单的 Python 写作,没有使用更低级、更复杂的语言的经验;其次,Rust 这种语言看起来很有前途,也很有趣。
我选择 QR 码编码器作为项目,是因为这个项目并不复杂,而且我可以熟悉 Rust 的基础知识。
此外,由于我们的未来计划与二维码有关,我想从这个项目中学到:如何使用位、矩阵、Rust 及其库、Reed-Solomon 算法和常见的纠错算法。
什么是 QR 码,以及如何生成?QR 码(Quick Response code,快速反应码)是一种二维条形码,它可以存储一些信息,借助搜索模式,可以用扫描仪轻松读取。
QR 码的优点是读取速度快、存储信息量大,而且使用 Reed-Solomon 算法,QR 码的纠错率高达 30%。
要生成 QR 代码,需要经过以下步骤:
数据编码
添加服务信息并填充
将信息分块
创建校正字节
组合区块
在 QR 码上放置信息
我对架构的设计
我对于生成器的架构设计有不同的想法,从中我选择了我认为最简单易懂的一种。
我想架构分为四个层次:
QrMatrix ⏤ 主矩阵,由模块组成,可以使用坐标进行更改。
DataBitvec ⏤ 使用编码将位转换为位向量(二进制位组成的向量),并添加纠错功能,然后将其发送到 DataEncoder。
DataEncoder ⏤ 该结构将使用 ZigZagIt 迭代器在 QrMatrix 中对数据进行编码。
QrBuilder ⏤ 作为 fieldQrMatrix (矩阵域)接收,它将所有基本元素添加到其中,对信息进行编码并创建掩码。
这些基本结构在 QrBuilder 结构中相互影响,从而得到一个现成的 QR 码矩阵,最后只需显示一个 QR 码即可。
创建主矩阵 QrMatrix
一开始,我想创建自己的 QrMatrix 数据结构,它只需由一个 Vec
通过函数中引入size值,我们可以创建自己想要的矩阵大小,并从中填入模块。模块中定义了枚举类,用于将功能块与普通信息分开,因此更加方便,而且无法更改功能块。
在我的结构中没有使用模块中的预留,因为在找到二维码的最佳掩码之前,信息块是不会被填满的。
要更改矩阵中的模块,可以使用以下函数:
为了显示二维码,我使用了终端:
这就是最终二维码的样子。
插入FinderBuilder 和 TimingBuilder
为了在二维码中生成搜索模式,我创建了一个数组形式的常量:
由于总是有三种搜索模式,而且它们的初始坐标很容易计算,因此我认为直接在 QrMatrix 中生成没有意义,只需将常数 FINDER_BLOCK 旋转并完全插入特定坐标即可。
创建同步车道要容易得多,因为它们的坐标总是已知的,长度也很容易求出:
由于条纹总是以白色模块开始,因此每转一圈将值改为相反的值,就可以得到一个具有同步条纹正确模块的矢量。
建立 DataEncoder
要将某些内容编码成 QR 码,必须先将给定的字符串转换成位向量,为此要使用可接受不同字符的编码方式:
数字编码 ⏤ 只对数字进行编码,每 3 个字符使用 10 个 bit。
字母数字编码 ⏤ 对大写拉丁字母、数字、$%*+-./: 等特殊字符和空格进行编码。
字节编码 ⏤ 虽然信息密度较低,但可以编码任何字符(例如,在 UTF-8 中)。
其实还有中日韩和其他字符的汉字编码,但我没有使用这种编码。
为了存储 bit 并方便使用,我使用了 bit_thing 库。此外,为了方便处理信息,我创建了一个 QrCodeBitvec 结构,它包含三个字段:一个用于存储服务信息(编码类型和字符数)的字段、一个用于存储数据的字段和一个用于存储纠错字节的字段。
举个例子,为了说明这个系统是如何工作的,我将数字 1234 编码成一个二维码。
首先,你需要确定使用哪种类型的编码,以及每行有多少个字符。在下面的示例中,我们使用的是数字编码类型,字符长度为 4,然后将其转换为 BitVec:
0001 0000000100
数字编码的字符长度为 10 位。
现在,我们需要将数字 1234 转换为数字编码。方法很简单,将 3 个数字分成一组,那这样可以分为 123 和 4,然后把这些数字转换为 BitVec,大于 99 的数字使用 10 个 bit(二进制位),大于 9 的数字使用 7 bit,小于 9 的数字使用 4 个 bit。
现在我们得到了这个:
0001 0000000100 0001111011 0100
基于以上,我们有了长度为 28 位的 BitVec,但按照 QR 码的规范要求,我们必须完整填写数据。所以在这个示例中,我们需要将 BitVec 填充至 152 位。为此,我们需要做三件事:
添加终止符 ⏤ 用零填充 4 个位。
用零填充数据,使其可以被 8 整除。
然后循环交替添加 2 个字节 ⏤ 11101100 和 00010001。
这些操作必须重复进行,直到数据量等于 152。
最后的数据就是这个样子:
0001 0000000100 0001111011 0100 0000<11101100 and 00010001 to end>
这些数据就可以发送给 Reed-Solomon 算法了。
Reed-Solomon 算法
为了实现这一算法,我使用了 Reed-Solomon 库。
我并不是十分清楚这种算法在数学上是如何工作的,但我至少尝试理解这种算法的逻辑,并将其正确地用于这个生成器。也有其他创建 QR 码生成器的开发者分享过使用 Reed-Solomon 库的经历,但我不喜欢那个人写的代码,因为其中命名很糟糕,而且有很多奇怪的代码结构,让人很难理解其算法逻辑,也没有什么意义,所以我放弃了这个想法,直接采用了一个现成的库。
我们的数据共有 152 个 bit,我们将这个库的结构发送给编码器。该结构接受一个值⏤校正字节数,对于校正级别为 L 的 QR 码第一版,使用了 7 个校正字节:
然后,我们将 BitVec 的字节转换为十进制数,并将这些代码字发送到 encoder 结构:
我们得到了 7 个纠错字节,对于第一个版本,我们只需在 BitVec 的末尾插入这些纠错字节:
0001 0000000100 0001111011 0100 0000<11101100 and 00010001 to end of data><7 correction bytes>
我们用二维码对这些现成的数据进行编码。
ZIG_ZAG_IT 和 DATA_ENCODER
为了将信息编码到二维码中,我创建了一个迭代器,它将给出从右下方开始的坐标。通过 "之 "字形移动和跳过功能块以避免改变它们,我们就能得到插入信息的正确坐标:
现在,沿着 BitVec 并将“位”插入坐标,我们就得到了一个包含正确数据的 QR 码,现在我们只需屏蔽数据,就能得到一个现成可用 QR 码。
这就是数字 1234 在第一版中的样子,校正级别为 L,并带有第一个掩码。
结论
在这个项目的帮助下,我学到了很多有用的东西,至少我开始更好地理解编程,学会了用 Rust 编程,但我还有成长的空间,我真的希望在编程方面有进一步的发展。
未来,我们计划创建其他有趣的项目,例如,创建一个看起来像 ShotCode ,但效率更高的极坐标 2D代码矩阵。
本次项目代码已上传到 GitHub ,详见: /TimurBora/QrCodeRust/tree/main
关键词: