基于Excel的QR二维码生成工具——原理及算法详解(之七)
来源:互联网 发布:ubuntu修改hosts翻墙 编辑:程序博客网 时间:2024/06/05 15:40
在上一篇文章中,我们讨论了一个自定义二维码填充函数,这个函数返回一个Byte型二位数组,数组的内容正是二维码矩阵的所有功能图形和格式版本信息,其中深色单元模块填充数字为1,浅色为0.最后,这个数组中还有大量的单元模块填充了数字3,这些模块就是为了数据填充做准备的。从本节开始,我们将要讨论二维码填充的最后一个部分:数据码字的填充。
数据码字除了包含我们已经完成编码的数据之外,还包含根据里德所罗门算法计算出来的数据纠错码,两部分按照一定的规律连接起来,就成为需要填充的数据码字。对于每个不同的版本,QR规范中都规定了不同的码字连接排列规则。对大部分版本的二维码来说,数据都是打乱顺序排列的,下面以版本“”为例,简单介绍数据码字的乱序排列方式。
我们要将下面的文字编码为一个6-H级别的二维码:
“月落乌啼霜满天,江枫渔火对愁眠
姑苏城外寒山寺,夜半钟声到客船”
首先将文字编码,采用中文汉字编码模式,编码后的数据码字为:
接下来,将上面的数据码字和纠错码字排列好后,从左上角开始从上到下,再从左到右逐列读取所有的数据,并重新排列:
数据码字的填充规则是这样的:首先从QR矩阵的右下角开始,从下至上地左右交替填充两列单元模块,到达矩阵的顶部后,再转而从上至下地填充相邻的两列单元模块,直至矩阵底部,然后再掉头向上填充,如此周而复始,直至完成整个矩阵的填充,具体的填充方式如下图所示:
如果使用Excel的工作表函数来实现上述矩阵的填充,将会使公示过于复杂,因此首选的方法还是使用VBA来进行填充。由于我们已经有了一个VBA自定义函数fillQR实现了一个二维数组的功能图形和版本信息的填充,因此对这个自定义函数稍加扩展便可以实现完整QR的填充。最简单的填充算法是所谓的“逐列法”,因为本来QR数据的填充就是逐列进行的,因此,如果令QR数组有S列,且QR数组中已经填好了功能图形和版本、格式信息,数据区域全部填充数字3。那么填充的算法为:
从第S列开始循环,循环步长为-2列
判断填充的方向,第奇数次填充方向为自底向上,偶数次填充方向为自顶向下
若填充方向为自底向上,从第S行开始循环,循环步长为-1:
如果当前列当前行是数据区域,则填充一个数据位,否则检查当前列-1列,如果是数据区域,则填充一个数据位
循环至下一行
循环至下一列
由于QR码的第7列被一列定位图形所占据,因此在采用逐列法填充的时候,循环开始从第S列填充至第9列后,应该跳过第7列,接下去直接从第6列开始填充,一直填充到第4和第2列,完成整个数据码填充。最后给出VBA代码,这段代码是自定义函数FillQR的一部分,FillQR已经接受了一个“0/1”字符串作为完整数据码字的输入,因此这段代码可以直接复制到FillQR函数中使用,接受FillQR的输入参数,从数据码字字符串中逐个取出字符值并完成QR矩阵的填充。
x = 1 j = Val(Mid(bs, x, 1)) Direction = 1 With currCell For .c = S To 9 Step -2 If Direction = 1 Then For .r = S To 1 Step -1 If QRArray(.r, .c) = 3 Then QRArray(.r, .c) = j Xor mask(m, .r, .c) x = x + 1 j = Val(Mid(bs, x, 1)) End If If QRArray(.r, .c - 1) = 3 Then QRArray(.r, .c - 1) = j Xor mask(m, .r, .c - 1) x = x + 1 j = Val(Mid(bs, x, 1)) End If Next Else For .r = 1 To S If QRArray(.r, .c) = 3 Then QRArray(.r, .c) = j Xor mask(m, .r, .c) x = x + 1 j = Val(Mid(bs, x, 1)) End If If QRArray(.r, .c - 1) = 3 Then QRArray(.r, .c - 1) = j Xor mask(m, .r, .c - 1) x = x + 1 j = Val(Mid(bs, x, 1)) End If Next End If Direction = IIf(Direction = 1, 2, 1) Next For .c = 6 To 2 Step -2 If Direction = 1 Then For .r = S To 1 Step -1 If QRArray(.r, .c) = 3 Then QRArray(.r, .c) = j Xor mask(m, .r, .c) x = x + 1 j = Val(Mid(bs, x, 1)) End If If QRArray(.r, .c - 1) = 3 Then QRArray(.r, .c - 1) = j Xor mask(m, .r, .c - 1) x = x + 1 j = Val(Mid(bs, x, 1)) End If Next Else For .r = 1 To S If QRArray(.r, .c) = 3 Then QRArray(.r, .c) = j Xor mask(m, .r, .c) x = x + 1 j = Val(Mid(bs, x, 1)) End If If QRArray(.r, .c - 1) = 3 Then QRArray(.r, .c - 1) = j Xor mask(m, .r, .c - 1) x = x + 1 j = Val(Mid(bs, x, 1)) End If Next End If Direction = IIf(Direction = 1, 2, 1) Next End With
另外还需要注意的是,QR的混码技术还没有用完,在填充数据码字的时候,数据位并不是直接填充到数组中的,而还需要进行一次掩码运算。QR规范中一共提供了8种不同的掩码,使用掩码的目的只是为了让整个QR矩阵中的黑白单元模块分布更加均匀。掩码的过程很简单,根据QR规范中提供的公式计算掩码值之后与数据码字进行Xor运算就可以了,掩码的信息已经包含在格式信息中了,解码时只要进行同样的Xor运算就可以了。上面的代码调用了mask函数来计算掩码值,并将异或运算结果填入矩阵。
掩码函数的代码如下:
Private Function mask(m As Long, row As Long, col As Long) As Long' determine the value of mask pattern in the cord' m is type of mask, value from 1 ~ 8Dim x As LongDim y As Long x = col - 1 y = row - 1 Select Case m Case Is = 1 mask = IIf((x + y) Mod 2 = 0, 1, 0) Case Is = 2 mask = IIf(y Mod 2 = 0, 1, 0) Case Is = 3 mask = IIf(x Mod 3 = 0, 1, 0) Case Is = 4 mask = IIf((x + y) Mod 3 = 0, 1, 0) Case Is = 5 mask = IIf(((y \ 2) + (x \ 3)) Mod 2 = 0, 1, 0) Case Is = 6 mask = IIf((x * y) Mod 2 + (x * y) Mod 3 = 0, 1, 0) Case Is = 7 mask = IIf(((x * y) Mod 2 + (x * y) Mod 3) Mod 2 = 0, 1, 0) Case Is = 8 mask = IIf(((x * y) Mod 3 + (x + y) Mod 2) Mod 2 = 0, 1, 0) End SelectEnd Function
掩码的图形如下(图片来自QR规范):
在本文中,我们讨论了QR码数据填充和掩码的生成,使用“逐列法”算法进行了QR二位数组的填充。至此,我们已经完整地讨论了QR生成的全部过程。在下一篇文章也是最后一篇文章中,我们将讨论另一种数据码填充的算法“寻址法”,并结束整个系列文章
- 基于Excel的QR二维码生成工具——原理及算法详解(之七)
- 基于Excel的QR二维码生成工具——原理及算法详解(之二)
- 基于Excel的QR二维码生成工具——原理及算法详解(之三)
- 基于Excel的QR二维码生成工具——原理及算法详解(之四)
- 基于Excel的QR二维码生成工具——原理及算法详解(之五)
- 基于Excel的QR二维码生成工具——原理及算法详解(之六)
- 基于Excel的QR二维码生成工具——原理及算法详解(之一)
- 基于Excel的QR二维码生成工具——原理及算法详解(最终篇)
- 二维码(QR code)基本结构及生成原理
- 二维码(QR code)基本结构及生成原理
- QR的生成(二维码)
- Android应用--QR的生成(二维码)
- Android应用--QR的生成(二维码)
- Android应用--QR的生成(二维码)
- Android应用--QR的生成(二维码)
- 安卓系统下生成QR码(二)——自定义二维码的纠错等级
- 安卓系统下生成QR码(三)——自定义二维码的颜色
- Javascript生成二维码(QR)
- <C++ Primer_5th>习题_3.24
- CodeForces
- <C++ Primer_5th>习题_3.25
- <C++ Primer_5th>习题_3.31
- 3 文本编辑器vim
- 基于Excel的QR二维码生成工具——原理及算法详解(之七)
- <C++ Primer_5th>习题_3.35
- POJ—487-3279
- <C++ Primer_5th>习题_3.36
- QT问题记录之EnterEvent事件无效
- HDU5514 Frogs
- android开发笔记汇总(一)
- Java 课堂笔记 3
- 匿名内部类是什么?为什么其访问外部变量必须是finally的?