#
前言
二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型:比如:字符,数字,日文,中文等等。这两天学习了一下二维码图片生成的相关细节,觉得这个玩意就是一个密码算法,在此写一这篇文章 ,揭露一下。供好学的人一同学习之。
关于QR Code Specification,可参看这个PDF:http://raidenii.net/files/datasheets/misc/qr_code.pdf
#
基础知识
首先,我们先说一下二维码一共有40个尺寸。官方叫版本Version。Version 1是21 x 21的矩阵,Version 2是 25 x 25的矩阵,Version 3是29的尺寸,每增加一个version,就会增加4的尺寸,公式是:(V-1)*4 + 21(V是版本号) 最高Version 40,(40-1)*4+21 = 177,所以最高是177 x 177 的正方形。
下面我们看看一个二维码的样例:
[![](http://coolshell.cn//wp-content/uploads/2013/10/QR-Code-Overview.jpeg)](http://coolshell.cn//wp-content/uploads/2013/10/QR-Code-Overview.jpeg)
1 | ## |
##
功能性数据
**Format Information** 存在于所有的尺寸中,用于存放一些格式化数据的。
**Version Information** 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。
1 | ## |
##
示例一:数字编码
在Version 1的尺寸下,纠错级别为H的情况下,编码: 01234567
1\. 把上述数字分成三组: 012 345 67
2\. 把他们转成二进制: 012 转成 0000001100; 345 转成 0101011001; 67 转成 1000011。
3\. 把这三个二进制串起来: 0000001100 0101011001 1000011
4\. 把数字的个数转成二进制 (version 1-H是10 bits ): 8个数字的二进制是 0000001000
5\. 把数字编码的标志0001和第4步的编码加到前面: 0001 0000001000 0000001100 0101011001 1000011
1 | ## |
##
按8bits重排
如果所有的编码加起来不是8个倍数我们还要在后面加上足够的0,比如上面一共有78个bits,所以,我们还要加上2个0,然后按8个bits分好组:
00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 010000<span style="color:#FF0000;">00</span>
1 | ## |
##
1、Position Detection Pattern
首先,先把Position Detection图案画在三个角上。(无论Version如何,这个图案的尺寸就是这么大)
![](http://images.cnitblog.com/news/66372/201310/29105438-7b5a8ec528bc4784aed702150ba944bf.png)
#`
##
2、Alignment Pattern
然后,再把 Alignment 图案画上
![](http://coolshell.cn//wp-content/uploads/2013/10/alignment-pattern.png)
关于Alignment的位置,可以查看[QR Code Spec](http://raidenii.net/files/datasheets/misc/qr_code.pdf)的第81页的Table-E.1的定义表(下表是不完全表格)
![](http://coolshell.cn//wp-content/uploads/2013/10/Alignment-Position.png)
下图是根据上述表格中的 Version8 的一个例子(6,24,42)
![](http://images.cnitblog.com/news/66372/201310/29105439-1719e93bdf5749f68dcb6d5025c443f6.png)
#`
##
3、Timing Pattern
接下来是 Timing Pattern 的线(这个不用多说了)
![](http://images.cnitblog.com/news/66372/201310/29105440-c15552dfb2d743b88aeb0a36cd74ca62.png)
#`
##
4、Format Information
再接下来是 Formation Information,下图中的蓝色部分。
![](http://images.cnitblog.com/news/66372/201310/29105440-377d20ad105649ec9895eb72b154dd4f.png)
Format Information 是一个 15 个 bits 的信息,每一个 bit 的位置如下图所示:(注意图中的 Dark Module,那是永远出现的)
![](http://images.cnitblog.com/news/66372/201310/29105440-7561c34ba56c47b5a6278f07c370cd99.png)
这 15 个 bits 中包括:
- 5 个数据 bits:其中,2 个 bits 用于表示使用什么样的 Error Correction Level, 3 个 bits 表示使用什么样的 Mask
10 个纠错 bits。主要通过 BCH Code 来计算
然后 15 个 bits 还要与 101010000010010 做 XOR 操作。这样就保证不会因为我们选用了 00 的纠错级别,以及 000 的 Mask,从重造成全部为白色,这会增加我们的扫描器的图像识别的困难。
下面是一个示例:
关于 Error Correction Level 如下表所示:
关于 Mask 图案如后面的 Table 23 所示。
#`
##
5、Version Information
再接下来是 Version Information(版本 7 以后需要这个编码),下图中的蓝色部分。
![](http://images.cnitblog.com/news/66372/201310/29105440-ebb2a858b1454f8f9b326ff7923e7b14.png)
Version Information 一共是 18 个 bits,其中包括 6 个 bits 的版本号以及 12 个 bits 的纠错码,下面是一个示例:
![](http://images.cnitblog.com/news/66372/201310/29105440-d7f867d0c7574565a34054adfec67fc2.png)
而其填充位置如下:
![](http://images.cnitblog.com/news/66372/201310/29105440-8dd3bad838e54ad3ba2acc809594b5ba.png)
#`
##
6、数据和数据纠错码
然后是填接我们的最终编码,最终编码的填充方式如下:从左下角开始沿着红线填我们的各个 bits,1 是黑色,0 是白色。如果遇到了上面的非数据区,则绕开或跳过。
![](http://images.cnitblog.com/news/66372/201310/29105440-b64b7060d04d407b8eaf179358c8b1f6.png)
#`
##
7、掩码图案
这样下来,我们的图就填好了,但是,也许那些点并不均衡,所以,我们还要做 Masking 操作(靠,还嫌不复杂)QR 的 Spec 中说了,QR 有 8 个 Mask 你可以使用,如下所示:其中,各个 mask 的公式在各个图下面。所谓 mask,说白了,就是和上面生成的图做 XOR 操作。Mask 只会和数据区进行 XOR,不会影响功能区。
![](http://images.cnitblog.com/news/66372/201310/29105441-4dfe5e39dfd6463ea59371c9a7ad21d4.png)
其 Mask 的标识码如下所示:(其中的i,j分别对应于上图的x,y)
![](http://images.cnitblog.com/news/66372/201310/29105440-4e7ad668f51047a8bd74fe1f1a5f5f34.png)
下面是 Mask 后的一些样子,我们可以看到被某些 Mask XOR 了的数据变得比较零散了。
![](http://images.cnitblog.com/news/66372/201310/29105441-87fe053c9d174ffd85080fdb61359f82.png)
Mask 过后的二维码就成最终的图了。
好了,大家可以去尝试去写一下 QR 的编码程序,当然,你可以用网上找个 Reed Soloman 的纠错算法的库,或是看看别人的源代码是怎么实现这个繁锁的编码。
原文地址:[http://coolshell.cn/articles/10590.html](http://coolshell.cn/articles/10590.html)