分线剧情:新生研讨课——二维码的生成
这里接着大一下讲我做二维码的事情。
定了二维码的题目后,我在大一下学期就时不时地去查二维码编码相关的资料,我的目的很明确:不依靠别的库/工具,自己写一个编码字符串最终显示二维码图像的程序。刚开始都是以CSDN之类的博客为主。这种博文虽然看起来是各种琳琅满目,内容丰富,但大多读下来就感觉并没有把整块知识连在一起。我始终缺乏一本令人心服口服的参考资料。后来再到中国知网上查(有不少硕士生的毕业论文就是做二维码编码相关的课题的),终于在一篇论文的引用文献里找到了《GB快速响应矩阵码》这本权威的资料。我把这本资料打印了下来,立刻就有了头绪,也有了自信,因为它把二维码的各种specifications都说清楚了。
原来我们日常说的二维码的学名叫QR Code,QR就是Quick Responsive。
大部分的流程我都是看得懂的,无非就是将二进制位流分组、异或,按指定的顺序填充码字等操作,除了纠错码的计算没看懂以外。而图形的显示这块,我又可以利用之前做游戏时的那个图形库,所以把流程跑通不是问题。我最担心的问题是,中途编码若是出了什么差错,可能就会导致最后的黑白图案怎么也识别不出来。
寒假的时候,我花了10天写这个程序。刚开始和我预期的一样进展很顺利,一步步按照specifications来,填充各种数据。到了第5天左右的时候不得不去了解纠错码的编码算法了。
我就不详细介绍纠错码的编码原理了,一是因为难以用短篇幅讲清楚,二是我自己也忘得差不多了…你可以查看Wikipedia对RS纠错码的介绍。不过有一点是可以说的,计算纠错码,本质上就是在解一个n元一次线性方程组,但未知数所在的数域是一个叫伽罗华域的东西,运算规则也不一样。为了支持这样的运算规则,之前暑假学的MMA也派上了用场,被用来方便地预先生成计算结果(一些实现细节我在中期报告里面有介绍)。
最终纠错码的计算算是实现出来了,但由于缺少现成的算纠错码的工具,很难验证它算的对不对(事实证明确实算错了。。)。
我开始画二维码的各种功能图形(功能图形包括三个角落里的小正方形,和一些用于定位的图案等。这些图形的排列都预制好了),再将数据码字按规定的顺序填进其他部分。
下面展示的就是某个版本的二维码的功能图形:
最后果然,显示出来的二维码像模像样,可就是扫不出来!
我采用了很死板,但很有效的方法:用别的二维码生成工具对于相同的输入,生成同样规格的二维码,与我的程序生成的二维码逐个像素地比对哪些区域是不一样的,然后再根据像素来推算正确的数据码字是什么。
虽然很麻烦,但还是可以定位到问题:功能图形有画错的地方,以及纠错码字算的不对。功能图形好改,但是纠错码字不知道是怎么算错了。最后把别人写的高斯消元解方程组的代码替换掉我自己写的,就没问题了。
最后听到“扫一扫”APP发出清脆的提示音,整个人兴奋得不行,大呼过瘾——程序员的快乐就是这么纯粹和简单,之前是,现在也是。
你可以在这个Github仓库下载这个小程序的源代码。但是你可能需要花费很多时间弄好依赖才能成功编译。现在的感悟是:若是开发库/工具类的程序,能够让使用者方便地构建自己写的代码,尽量让装依赖的过程自动化,而不是把大量时间费在配环境装依赖上,也是开发者要考虑的问题之一。
还是附几张图展示一下吧:
-
这是一张未编码任何数据的二维码,数据码字区域仅包含必要的头部信息,我的小米手机在扫这张图案时的扫描结果似乎很有趣。
-
也许你从未见过下面这么大的二维码。
你可以看到二维码右侧有规律的纹理,这些区域因为都在反复编码
d
,所以就呈现出周期性。你又会发现左侧的二维码呈现出另一种不同的纹理,这些区域就是在反复编码纠错码了。