这是一个相当古老的项目了。
前序
之前一直想写一个有关二维码生成器的教程,由于各种各样的原因,当然主要原因是懒,一直没有下手。最近感觉还是要做点什么,不然有种要烂尾的冲动。
我之所以要写这个教程,主要是前些年有一个项目,需要用到二维码。当然网上的确已经有很多二维码生成器的版本了,但是写C和C++的还是少数,而且最坑爹的是这些人写代码都不带注释的。对于我来说,我的工作不仅仅限于生成一个二维码就完了,还需要利用二维码的一些特性对二维码进行处理,这样的话前人的代码就相当不友好了,索性我就自己造了轮子。当然我也是写了一部分注释,基本能解释每个函数是干了什么工作。但是这么做还是很难对二维码有一个整体性的认识,为了造福后人,我打算根据自己写的代码,详细的解析二维码,造福后人,避免大家趟我的坑。
github项目 欢迎fork,star,可以结合代码理解实现。
二维码的理论基础
想要比较深入理解二维码,理解二维码的纠错算法是很必要的。
二维码中使用的Reed Solomom 纠错算法是BCH码的一种,广泛用于通信,航空航天等领域。RS码具有低冗余,高纠错的特点。为什么二维码一部分缺失还能正确解码,二维码的纠错能力有多强,对于这些东西我们要知其然,也要知其所以然。
有限域理论
在正式开始讲解RS码之前,还是要补习一些数学知识 。
有限域又称为伽罗瓦域(Galois Field),是仅含有限个元素的域,是由伽罗瓦于十八世纪30年代研究代数方程根式求解问题时引出。
有限域的特征数必定是特征为 p p 的有限域,则为某一素数 ,因此它含的素域同构于 Zp Z p 。若 F F 中元素个数为 元素, n n 为某一正整数。元素个数相同的有限域是同构的,通常用 表示 pn p n 元的有限域。
在此歪个题,伽罗瓦可是个传奇数学家,死的也很有传奇性。想了解的筒子可以看死于决斗的天才少年伽罗瓦。
在本教程里,生成有限域依靠GenericGF类。GenericGF是生成伽罗瓦域的标准操作。下面我们将参照GenericGF里的相关函数来具体学习如何生成二维码生成所需的伽罗瓦域。
class GenericGF final {
private:
int size;
int primitive;
int geneBase;
std::vector<int> expTab;
std::vector<int> logTab;
public:
GenericGF(int primitive, int size, int b);
...
}
GeneicGF 类有5个成员函数,其中前三个为构造函数传入的参数,后两个用来存储计算结果。下面我们根据具体参数来讲解二维码有限域生成。
primitive 有限域的本原多项式。
在有限域中除了0,1之外,其余所有的元素都是有本原多项式生成,本原多项式特征满足 x2p−1+1P(x) x 2 p − 1 + 1 P ( x ) 的余数为0,这点可能比较难以理解,但是我们可以记住二维码生成的有限域的本原多项式可以表示为 P(x)=x8+x4+x3+x2+1 P ( x ) = x 8 + x 4 + x 3 + x 2 + 1 ,所以primitive=0x011D,直接输入就行。
size 有限域中元素的个数 p