精华内容
下载资源
问答
  • 二维码生成原理

    万次阅读 2018-03-20 12:07:04
    QR码生成原理(一) 一、什么是QR码 QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。QR码的样子其实在很多场合已经能够被看到了,我这还是贴个图展示一下: 这个图如果被正确...

    QR码生成原理(一)

    一、什么是QR码

    QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。QR码的样子其实在很多场合已经能够被看到了,我这还是贴个图展示一下:

    这个图如果被正确解码,应该看到我的名字和邮箱。

    二、QR码的特点

    说到QR码的特点,一是高速读取(QR就是取自“Quick Response”的首字母),对读取速度的体验源自于我手机上的一个软件,象上面贴出的码图,通过摄像头从拍摄到解码到显示内容也就三秒左右,对摄像的角度也没有什么要求;

    二是高容量、高密度;理论上内容经过压缩处理后可以存7089个数字,4296 个字母和数字混合字符,2953个8位字节数据,1817个汉字;

    三是支持纠错处理;纠错处理相对复杂,目前我还没有深入了解,按照QR码的标准文档说明,QR码的纠错分为4个级别,分别是:

    • level L : 最大 7% 的错误能够被纠正;
    • level M : 最大 15% 的错误能够被纠正;
    • level Q : 最大 25% 的错误能够被纠正;
    • level H : 最大 30% 的错误能够被纠正;

    四是结构化;看似无规则的图形,其实对区域有严格的定义,下图就是一个模式2、版本1的QR图结构(关于QR码的”模式”、”版本”将在后面进行介绍):

    在上图21*21的矩阵中,黑白的区域在QR码规范中被指定为固定的位置,称为寻像图形(finder pattern) 和 定位图形(timing pattern)。寻像图形和定位图形用来帮助解码程序确定图形中具体符号的坐标。

    黄色的区域用来保存被编码的数据内容以及纠错信息码。

    蓝色的区域,用来标识纠错的级别(也就是Level L到Level H)和所谓的”Mask pattern”,这个区域被称为“格式化信息”(format information)。

    五是扩展能力。QR码的Structure Append特点,使一个QR码可以分解成多个QR码,反之,也可以将多个QR码的数据组合到一个QR码中来

     

    三、QR码的模式和版本

    前面提到过QR码的模式(Model)和版本(Version)。QR码分为Model1和Model2两种模式,Model1是对QR的初始定义,Model2是对Model1的扩展,目前使用较为普遍的是Model2,本文的所有说明也仅用于Model2。

    QR图的大小(size)被定义为版本(Version),版本号从1到40。版本1就是一个21*21的矩阵,每增加一个版本号,矩阵的大小就增加4个模块(Module),因此,版本40就是一个177*177的矩阵。(版本越高,意味着存储的内容越多,纠错能力也越强)。

    三、QR码支持的编码内容

    QR码支持编码的内容包括纯数字、数字和字符混合编码、8位字节码和包含汉字在内的多字节字符。其中:

    数字:每三个为一组压缩成10bit。

    字母数字混合:每两个为一组,压缩成11bit。                                  

    8bit字节数据:无压缩直接保存。

    多字节字符:每一个字符被压缩成13bit。

    QR码编码原理(二)

    编码就是把常见的数字、字符等转换成QR码的方法。说具体的编码之前,先说一下QR码的最大容量问题。

    一、最大容量

    QR码的最大容量取决于选择的版本、纠错级别和编码模式(Mode:数字、字符、多字节字符等)。以版本1、纠错级别为Level Q的QR码为例,可以存储27个纯数字,或17个字母数字混合字符或11个8bit字节数据。如果要存储同样多的内容同时提高纠错级别,则需要采用更高的版本。版本1~9 数据容量、纠错码容量对照如下表:

    (version)(error correcting level)(count of data code words)count of EC code words(numeric)(alphanumeric)8bit
    1L197412517
    M1610342014
    Q1313271611
    H91717107
    2L3410774732
    M2816633826
    Q2222482920
    H1628342014
    3L55151277753
    M44261016142
    Q3436774732
    H2644583524
    4L802018711478
    M64361499062
    Q48521116746
    H3664825034
    5L10826255154106
    M864820212284
    Q62721448760
    H46881066444
    6L13636322195134
    M10864255154106
    Q769617510874
    H601121398458
    7L15640370224154
    M12472293178122
    Q8810820712586
    H661301549364
    8L19448461279192
    M15488365221152
    Q110132259157108
    H8615620212284
    9L23260552335230
    M182110432262180
    Q132160312189130
    H10019223514398

    如果要了解更详细的QR码容量信息,可以到电装的网站去看看http://www.denso-wave.com/qrcode/vertable1-e.html

     

    下面,就举例说明将“ABCDE123”转换成为版本1、Level H的QR码转换方法。

    二、模式标识符(Mode Indicator)

    QR码的模式(Mode)就是前文提到的数字、字符、8bit 字节码、多字节码等。对于不同的模式,都有对应的模式标识符(Mode Indicator)来帮助解码程序进行匹配,模式标识符是4bit的二进制数:

    1、数字模式(numeric mode ): 0001
    2、混合字符模式(alphanumeric mode) : 0010
    3、8bit byte mode: 0100
    4、日本汉字(KANJI mode) : 1000

    5、中国汉字(GB2312):1101

    由于示例文本串是混合字符,因此将选择alphanumeric mode,其标识码为:0010

    三、文本串计数标识符(Character count indicator)

    文本串计数标识符用来存储源内容字符串的长度,在版本1-9的QR码中,文本串长度标识符自身的长度被定义为:
    数字 : 10bit 
    混合字符 : 9bit
    8bit 字节码 : 8bit
    多字节码 : 8bit

    在本例中,源文本串的长度为8个字符,混合字符的长度为9bit,因此将字符个数8编码为9位二进制表示:000001000

    加上混合字符模式标识码,总的编码为0010 000001000

    四、数据内容编码

     1、数字模式下的编码

    在数字模式下,数据被限制为3个数字一段,分成若干段。如:”123456” 将分成”123” 和 “456”,分别被编码成10bit的二进制数。“123”的10bit二进制表示法为:0001111011,实际上就是二进制的123。

    当数据的长度不足3个数字时,如果只有1个数字则用4bit,如果有2个数字就用7个bit来表示。
    如:”9876”被分成”987”和”6”两段,因此被表示为”1111011011 0110”。

    2、混合字符模式下的编码

    混合字符模式编码,其字符对照表如下:

     0 
     A   10 
     K   20 
     U   30 
     +   40 
    1 1
    B 11
    L 21
    V 31
    - 41
    2 2
    C 12
    M 22
    W 32
    . 42
    3 3
    D 13
    N 23
    X 33
    / 43
    4 4
    E 14
    O 24
    Y 34
    : 44
    5 5
    F 15
    P 25
    Z 35
    6 6
    G 16
    Q 26
    [sp] 36
    7 7
    H 17
    R 27
    $ 37
    8 8
    I 18
    S 28
    % 38
    9 9
    J 19
    T 29
    * 3

     

    编码方式为:

    源码被分成两个字符一段,如下所示,每段的第一个字符乘上45,再用第二个数字相加。因此每段变成了11bit的2进制码,如果字符个数只有1个,则用6bit表示。

     

    示例: 



    “AB” “CD” “E1” “23”


    45*10+11 45*12+13 45*14+1 45*2+3


    461 553 631 93
    0010 000001000 00111001101010001010010100111011100001011101

    3、8bit字节数据不经编码转换直接保存。

    五、编码终止符(Terminator)

    如果编码后的字符长度不足当前版本和纠错级别所存储的容量,则在后续补”0000”,如果容量已满则无需添加终止符。此时得到的编码串为:

    0010 000001000 00111001101 01000101001 01001110111 000010111010000
    六、编成8bit码字(Code words)

    将以上的编码再按8bit一组,形成码字(code words):

     00100000 01000001 11001101 01000101 00101001 11011100 00101110 10000
    如果尾部数据不足8bit,则在尾部充0:

    00100000 01000001 11001101 01000101 00101001 11011100 00101110 10000000
    如果编码后的数据不足版本及纠错级别的最大容量,则在尾部补充 “11101100” 和 “00010001”,直到全部填满。最后,版本1、Level H下的”ABCDE123” 的QR码是:

    00100000 01000001 11001101 01000101 00101001 11011100 00101110 1000000011101100

    十进制表示法为:

    32 65 205 69 41 220 46 128 236

    QR码编码原理三(日本汉字和中文编码)

    一、日本汉字(KANJI)是两个字节表示的字符码,编码的方式是将其转换为13字节的二进制码制。

    转换步骤为:

    1、对于JIS值为8140(hex) 到9FFC(hex)之间字符:

    a)将待转换的JIS值减去8140(hex);

    b)将高位字节乘以C0(hex);

    c)将b)步骤生成的数据加上低位字节;

    d)将结果转换为13位二进制串。

    2、对于JIS值为E040(hex)到EBBF(hex)之间的字符:

    a)将待转换的JIS值减去C140(hex);

    b)将高位字节乘以C0(hex);

    c)将b)步骤生成的数据加上低位字节;

    d)将结果转换为13位二进制串。

     

    二、中文汉字的与日文汉字转换步骤相似:

    1、对于第一字节为0xA1~0xAA之间,第二字节在0xA1~0xFE之间字符:

    a)第一字节减去0xA1;

    b)上一步结果乘以0x60;

    c)第二字节减去0xA1;

    d)将b)步骤的结果加上c步骤的结果;

    e)将结果转换为13位二进制串。

    1、对于第一字节为0xB0~0xFA之间,第二字节在0xA1~0xFE之间字符:

    a)第一字节减去0xA6;

    b)上一步结果乘以0x60;

    c)第二字节减去0xA1;

    d)将b)步骤的结果加上c步骤的结果;

    e)将结果转换为13位二进制串。

    一、使用jquery-qrcode生成二维码

    先简单说一下jquery-qrcode,这个开源的三方库(可以从https://github.com/jeromeetienne/jquery-qrcode 获取),

    qrcode.js 是实现二维码数据计算的核心类,

    jquery.qrcode.js 是把它用jquery方式封装起来的,用它来实现图形渲染,其实就是画图(支持canvas和table两种方式)


    支持的功能主要有:

     

    Js代码   收藏代码

    1. text     : https://github.com/jeromeetienne/jquery-qrcode  //设置二维码内容  

     

    Js代码   收藏代码

    1. render   : “canvas”,//设置渲染方式  
    2. width       : 256,     //设置宽度  
    3. height      : 256,     //设置高度  
    4. typeNumber  : -1,      //计算模式  
    5. correctLevel    : QRErrorCorrectLevel.H,//纠错等级  
    6. background      : ”#ffffff”,//背景颜色  
    7. foreground      : ”#000000” //前景颜色  


     

    使用方式非常简单

     

    Js代码   收藏代码

    1. jQuery(‘#output’).qrcode({width:200,height:200,correctLevel:0,text:content});  


     

     经过简单实践,

    使用canvas方式渲染性能还是非常不错的,但是如果用table方式,性能不太理想,特别是IE9以下的浏览器,所以需要自行优化一下渲染table的方式,这里就不细述了。

     

    二、JS生成中文二维码

    其实上面的js有一个小小的缺点,就是默认不支持中文。

    这跟js的机制有关系,jquery-qrcode这个库是采用 charCodeAt() 这个方式进行编码转换的,

    而这个方法默认会获取它的 Unicode 编码,一般的解码器都是采用UTF-8, ISO-8859-1等方式,

    英文是没有问题,如果是中文,一般情况下Unicode是UTF-16实现,长度2位,而UTF-8编码是3位,这样二维码的编解码就不匹配了。

    解决方式当然是,在二维码编码前把字符串转换成UTF-8,具体代码如下:

     

    Js代码   收藏代码

    1. function utf16to8(str) {  
    2.     var out, i, len, c;  
    3.     out = ”“;  
    4.     len = str.length;  
    5.     for(i = 0; i < len; i++) {  
    6.     c = str.charCodeAt(i);  
    7.     if ((c >= 0x0001) && (c <= 0x007F)) {  
    8.         out += str.charAt(i);  
    9.     } else if (c > 0x07FF) {  
    10.         out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));  
    11.         out += String.fromCharCode(0x80 | ((c >>  6) & 0x3F));  
    12.         out += String.fromCharCode(0x80 | ((c >>  0) & 0x3F));  
    13.     } else {  
    14.         out += String.fromCharCode(0xC0 | ((c >>  6) & 0x1F));  
    15.         out += String.fromCharCode(0x80 | ((c >>  0) & 0x3F));  
    16.     }  
    17.     }  
    18.     return out;  

    三、参考

    https://github.com/jeromeetienne/jquery-qrcode

    http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt

    二维码生成原理


                </div>
    

    转自骆定华的博客:http://blog.csdn.net/jason_ldh/article/details/11801355

    展开全文
  • 二维码生成原理及解析代码

    万次阅读 多人点赞 2017-12-18 22:35:06
    二维码生成原理及解析代码 自从大街小巷的小商小贩都开始布满了腾讯爸爸和阿里爸爸的二维码之后,我才感觉到我大天朝共享支付的优越性。最近毕业论文写的差不多了,在入职之前多学一些东西也是好的。这里秉着好奇心...

    二维码生成原理及解析代码

    自从大街小巷的小商小贩都开始布满了腾讯爸爸和阿里爸爸的二维码之后,我才感觉到我大天朝共享支付的优越性。最近毕业论文写的差不多了,在入职之前多学一些东西也是好的。这里秉着好奇心,研究一下二维码的生成,并尝试性写一个二维码解析源码。

    注:暂时只有二维码原理,笔者这段时间会持续研究解析代码,并随进度持续更新。

    参考网址:
    《二维码的生成细节和原理》
    《QR Code Tutorial》
    《Hello World!》—— 知乎专栏文章
    《为程序员写的Reed-Solomon码解释》

    一. 二维码基本知识

    二维码另一个名称是QR Code(Quick Response Code),近年来在移动设备上经常使用,与传统条形码相比,可以存储更多的信息。二维码本质上是个密码算法,基本知识总结如下。
    首先,二维码存在 40 种尺寸,在官方文档中,尺寸又被命名为 Version。尺寸与 Version 存在线性关系:Version 1 是 21×21 的矩阵,Version 2 是 25×25 的矩阵,每增加一个 Version,尺寸都会增加 4,故尺寸 Size 与 Version 的线性关系为:

    Size=(Version1)×4

    Version 的最大值是 40,故尺寸最大值是(40-1)*4+21 = 177,即 177 x 177 的矩阵。

    二维码结构如下图 1.1 所示:



    图1.1 二维码结构

    二维码的各部分都有自己的作用,基本上可被分为定位、功能数据、数据内容三部分。

    • 定位图案:
      • Position Detection Pattern, 定位图案:用于标记二维码矩形的大小;用三个定位图案即可标识并确定一个二维码矩形的位置和方向了;
      • Separators for Position Detection Patterns, 定位图案分割器:用白边框将定位图案与其他区域区分;
      • Timing Patterns, 时序图案:用于定位,二维码如果尺寸过大,扫描时容易畸变,时序图案的作用就是防止扫描时畸变的产生;
      • Alignment Patterns, 对齐图案:只有在 Version 2 及其以上才会需要;
    • 功能数据:
      • Format Information, 格式信息:存在于所有尺寸中,存放格式化数据;
      • Version Information, 版本信息:用于 Version 7 以上,需要预留两块 3×6 的区域存放部分版本信息;
    • 数据内容:剩余部分存储数据内容
      • Data Code, 数据码;
      • Error Correction Code, 纠错码;

    二. 数据编码

    2.1 数据编码信息

    二维码的数据编码信息如下图 2.1, 2.2 中的列表所示:



    图2.1 模式编号指示器



    图2.2 字符计数指示器中的位数

    上图 2.1 中,展示的是二维码支持的数据编码模式。
    :其中中文编码模式为 1101;

    上图 2.2 中展示了不同版本(即不同尺寸)的二维码,单个编码对应二进制的位数。
    :二维码规格说明书中,存在各式各样的编码规范表;

    图2.1, 2.2 表格具体含义,在后面的例程中会具体讲解。

    2.2 数据编码形式

    2.2.1 数字编码(Numeric Mode)

    数字编码的范围为 0~9。
    对于数字编码,统计需要编码数字的个数是否为 3 的倍数:如果不是 3 的倍数,则剩下的 1 位或 2 位会被转为 4bits 或 8bits(十进制转二进制),每三位数字都会被编成 10bits, 12bits, 14bits,具体编码长度仍然需要二维码尺寸决定。

    2.2.2 字符编码(Alphanumeric Mode)

    字符编码的范围有:

    • 数字 0~9;
    • 大写 A~Z(无小写);
    • 几个符号$ % * + - . / 和空格。

    上述字符映射为一个索引表,如下图 2.3 所示:



    图2.3 字符映射索引表

    图中 Char 表示字符,Value 表示字符对应的索引值。
    索引表中共 45 种对应关系,字符编码的过程,就是将每两个字符分为一组,然后转成上图 2.3 的 45 进制,再转为 11bits 的二进制结果。对于落单的一个字符,则转为 6bits 的二进制结果。
    此外,根据上图 2.2 的设定,对不同 Version 的二维码使用 9/11/13 个二进制表示。

    注:
    上图 2.3 中的 SP 代表空格。

    2.2.3 字节编码(Byte Mode)

    可以是 0-255 的 ISO-8859-1 字符。有些二维码的扫描器可以自动检测是否是 UTF-8 的编码。

    2.2.4 日文编码(Kanji Mode)

    日文编码同时也是双字节编码,同样也可以用于中文编码。
    日文与中文编码流程基本相似:

    1. 首先减去一个值;
    2. 挑出差值结果的前两个 16 进制,乘以 0xC0;
    3. 加上后两个 16 进制位;
    4. 转为 13bits 编码;

    按照日文编码集 SHIFT_JIS为参照,可查询日文字符的对应编码。以“雅”与“芒”为例,转换过程如下图 2.4 所示:



    图2.4 日文编码流程展示

    2.2.5 其他编码

    其他类型的编码本文中不详细说明。其中包括:

    • 特殊字符集(Extended Channel Interpretation Mode):主要用于特殊的字符集,并不是所有的扫描器都支持这种编码;
    • 混合编码(Structured Append Mode):说明该二维码中包含了多种编码格式;
    • 特殊行业编码(FNC1 Mode):主要是给一些特殊的工业或行业用的,如GS1条形码等;

    2.3 数据编码示例说明

    分别用一个数字编码与字符编码的示例,说明数据编码的过程:

    2.3.1 例程1:数字编码

    问题:对于 Version 1 尺寸的二维码,纠错级别为 H,编码为:01234567
    解析步骤:

    1. 将上述数字分为三组:012, 345, 67;
    2. 查询图 2.2 表格内容,Version 1 二维码的数字编码应转换为 10bits 的二进制数字,故将上面三组数字转为二进制分别为:012→0000001100, 345→0101011001, 67→1000011;
    3. 将三个二进制串连接起来:0000001100 0101011001 1000011;
    4. 将数字的个数转成二进制:对于数字编码,数字长度依旧用图 2.2 表格中查到的 10bits 二进制数字来表示,数字共有 8 个,故数字个数的二进制形式为:8→0000001000;
    5. 查询图 2.1 表格内容,数字编码的标志为 0001,将编码标志与步骤 4 编码结果加到步骤 3 结果之前,故最终结果为:0001 0000001000 0000001100 0101011001 1000011

    2.3.2 例程2:字符编码

    问题:对于 Version 1 尺寸的二维码,纠错级别为 H,编码为:AE-86
    解析步骤:

    1. 在图 2.3 的字符索引表中分别找到 AE-86 五个字符的索引分别为:(10, 14, 41, 8, 6);
    2. 将五个字符两两分组:(10, 14) (41, 8) (6);
    3. 字符编码应将字符组转换为 11bits 的二进制,故上述三组字符首先转为 45 进制后再转为二进制:
      • (10, 14):转为 45 进制:10×45+14=464;再转为 11bits 的二进制:00111010000;
      • (41, 8):转为 45 进制:41×45+8=1853;再转为 11bits 的二进制:11100111101;
      • (6):转为 45 进制:6;再转为 6bits 的二进制:000110;
    4. 将步骤 3 中得到的三个二进制结果连接起来:00111010000 11100111101 000110;
    5. 查询图 2.2 表格内容,Version 1 二维码的字符个数应转换为 9bits 的二进制数字,对于 5 个字符,二维码字符个数转为 9bits 二进制为:000000101;
    6. 查询图 2.1 表格内容,字符编码的标志为 0010,将编码标志与步骤 5 编码结果加到步骤 4 结果之前,故最终编码结果为:0010 000000101 00111010000 11100111101 000110;

    三. 结束符与补齐符

    对于结束符和补齐符,我们直接举例进行说明。
    问题:对于 Version 1 尺寸的二维码,纠错级别为 H,以笔者的英文名作为编码:CHANDLERGENG
    按照 2.3.2 字符编码例程进行分析,得到编码如下:

    编码字符数CHANDLERGENG 的编码
    001000000110101000101101 00111011001 01001011110 01010010001 01011011110 10000011011

    3.1 结束符

    在需要在对于上述字符的编码,需要在最后加上结束符。结束符为连续 4 个 0 值。加上结束符后,得到的编码如下:

    编码字符数CHANDLERGENG 的编码结束
    001000000110101000101101 00111011001 01001011110 01010010001 01011011110 100000110110000

    如果所有的编码加起来不是 8 的倍数,则还需要在后面加上足够的 0。如上面一共有 83bits,所以与 8 的倍数还相差两位,故在最后加上 5 个 0,上表最终的数据变为:
    00100000 01101010 00101101 00111011 00101001 01111001 01001000 10101101 11101000 00110110 00000000

    3.2 补齐符

    如果最后还没有达到我们最大的 Bits 数限制,则需要在编码最后加上补齐符(Padding Bytes)。
    补齐符内容是不停重复两个字节:1110110000010001。这两个二进制转成十进制,分别为 236 与17,具体不知道为什么选这两个值……关于每一个Version的每一种纠错级别的最大Bits限制,可以参看 QR Code Spec 的第35页到44页的 Table-7 一表(笔者参考的是《ISO/IEC 18004》2000版),大致如下图 3.1 所示:



    图3.1 二维码纠错级别的最大Bits限制(部分)

    上图 3.1 中提到的 codewords,可译为码字,一个码字是一个字节。对于 Version 1 的 H 纠错级别,共需要 26 个码字,即 104bits。现在加上用 0 补全的结束符,已经有了 88bits,故还需要补上 16 bits。补齐后的编码为:

    00100000 01101010 00101101 00111011 00101001 01111001 01001000 10101101 11101000 00110110 00000000 11101100 00010001

    以上数据即为数据码(Data Codewords)

    四. 纠错码

    前文提到了不同的纠错级别(Error Correction Code Level)。有了纠错机制,才可以使得有些二维码有了残缺也可以扫码解析出来,才可以使得二维码中心位置可以供某些商家加上对解析不必要的图标。
    二维码一共有四种纠错级别:

    纠错水平可被修正容量
    L7% 码字
    M15% 码字
    Q25% 码字
    H30% 码字

    二维码对数据码加上纠错码的过程,首先要对数据码进行分组,即分成不同的块(Block)。参看如上图 3.1 所示 QR Code Spec 的第35页到44页的 Table-7 中的最下方说明了分组的定义表:



    图4.1 二维码纠错级别说明(部分)

    对于表中的最后两列的内容:

    • 纠错块个数(Number of error correction blocks):需要划分纠错快的个数;
    • 纠错块码字数(Error Correction Code Per Blocks):每个块中的码字个数,即有多少个字节Bytes;

    表中最下面关于 (c,k,r) 的解释:

    • c:码字总个数;
    • k:数据码个数;
    • r:纠错码容量

    注:

    • c,k,r的关系公式: c=k+2×r
    • 纠错码容量小于纠错码个数的一般

    以上图 4.1 中的 Version 5 + H 纠错机为例:图中红色方框说明共需要 4 个块(上下行各一组,每组 2 个块)。

    第一组的属性:

    • 纠错块个数 = 2:该组中有两个块;
    • (c, k, r) = (33, 11, 11):该组中每个块共有 33 个码字,其中 11 个数据码, 11×2=22 个纠错码;

    第二组的属性:

    • 纠错块个数 = 2:该组中有两个块;
    • (c, k, r) = (34, 12, 11):该组中每个块共有 34 个码字,其中 12 个数据码, 11×2=22 个纠错码;

    具体示例如下表所示,且由于使用二进制会使得表格过大,故转为范围在 0~255 的十进制。其中组 1 的每个块,都有 11 个数据码, 22 个纠错码;组 2 的每个块,都有 12 个数据码,22 个纠错码。

    数据每个块的纠错码
    11

    2
    67 85 70 134 87 38 85 194 119 50 6

    66 7 118 134 242 7 38 86 22 198 199
    199 11 45 115 247 241 223 229 248 154 117 236 38 6 50 17 7 236 213 87 148 235

    177 212 76 133 75 242 238 76 195 230 189 106 248 134 76 40 154 27 195 255 117 129
    21

    2
    247 119 50 7 118 134 87 38 82 6 134 151

    194 6 151 50 16 236 17 236 17 236 17 236
    96 60 202 182 124 157 200 134 27 129 209 182 70 85 246 230 247 70 66 247 118 134

    173 24 147 59 33 106 40 255 172 82 2 157 242 33 229 200 238 106 248 134 76 40

    二维码的纠错码主要是通过里德-所罗门纠错算法(Reed-Solomon Error Correction)实现的。

    (关于 Reed-Solomon 算法,现在此处占坑,回头研究了再写上去)

    五. 最终编码

    此时得到了数据,但还不能开始画图,因为二维码还需要将数据码与纠错码的各个字节交替放置。

    5.1 穿插放置

    继续以第四章中给出的示例为例,给出其穿插放置的过程。

    5.1.1 数据码穿插放置

    第四章示例中的数据码如下表所示:

    块数
    块1678570134873885194119506
    块26671181342427388622198199
    块32471195071181348738826134
    块419461515016236172361723617

    提取每一列数据:

    • 第一列:67, 66, 247, 194;
    • 第二列:85, 7, 119, 6;
    • ……
    • 第十一列:6, 199, 134, 17;
    • 第十二列:151, 236;

    将上述十二列的数据拼在一起:67, 66, 247, 194, 85, 7, 119, 6,…, 6, 199, 134, 17, 151, 236。

    纠错码如下表所示:

    块数
    块11991145115247241223229248154117
    块2177212761337524223876195230189
    块3966020218212415720013427129209
    块417324147593310640255172822

    同样的方法,将 22 列数据放在一起:199, 177, 96, 173, 11, 212, 60, 24, …, 148, 117, 118, 76, 235, 129, 134, 40。

    上述部分即为二维码的数据区。

    5.2 剩余位 (Remainder Bits)

    对于某些 Version 的二维码,得到上面的数据区结果长度依旧不足,需要加上最后的剩余位。比如对于 Version 5 + H 纠错等级的二维码,剩余位需要加 7bits,即加 7 个 0。参看 QR Code Spec 的 Table-1 一表即可查询不同 Version 的剩余位信息,如下图 5.1 所示:



    图5.1 不同 Version 的剩余位

    六. 二维码的绘制

    终于讲到二维码绘制过程了,绘制的过程按照顺序对图 1.1 中各个重要部分依次讲解。

    6.1 定位图案 (Position Detection Pattern)

    首先在二维码的三个角上绘制定位图案。定位图案与尺寸大小无关,一定是一个 7×7 的矩阵。如下图 6.1 所示:



    图6.1 定位图案 (Position Detection Pattern)

    6.2 对齐图案 (Alignment Pattern)

    然后绘制对齐图案。对齐图案与尺寸大小无关,一定是一个 5×5 的矩阵。如下图 6.2 所示:



    图6.2 对齐图案 (Alignment Pattern)

    对齐图案绘制的位置,可参看 QR Code Spec 的 Table-E.1 一表查询,部分内容如下图 6.3 所示:



    图6.3 对齐图案位置索引表(部分)

    下图 6.4 是上述表格中 Version 8 的一个例子,对于 Version 8 的二维码,行列值在 6, 24, 42 的几个点都会有对齐图案。



    图6.4 对齐图案例程 1

    下图 6.5 是最近我老妈怂恿我用支付宝抢红包时给我发来的二维码,该二维码中只有一个对齐图案, 故 Version 应在 V2——V6 之间。



    图6.5 对齐图案例程 2

    6.3 时序图案 (Timing Pattern)

    时序图案是两条连接三个定位图案的线,如下图 6.6 所示:



    图6.6 时序图案例程 1

    依旧拿支付宝红包的二维码为例,其时序图案如图 6.7 所示:



    图6.7 时序图案例程 2

    这里写图片描述

    6.4 格式信息

    格式信息如下图 6.8 所示:



    图6.8 格式信息

    格式信息在定位图案周围分布,由于定位图案个数固定为 3 个,且大小固定,故格式信息也是一个固定 15bits 的信息。每个 bit 的位置如下图 6.9 所示:(注:图中的 Dark Module 是固定永远出现的



    图6.9 格式信息位置

    15bits 中数据,按照 5bits 的数据位 + 10bits 纠错位的顺序排列:

    • 数据位占 5bits:其中 2bits 用于表示使用的纠错等级 (Error Correction Level),3bits 用于表示使用的蒙版 (Mask) 类别;
    • 纠错位占 10bits:主要通过 BCH Code 计算;

    为了减少扫描后图像识别的困难,最后还需要将 15bits 与 101010000010010 做异或 XOR 操作。因为我们在原格式信息中可能存在太多的 0 值(如纠错级别为 00,蒙版 Mask 为 000),使得格式信息全部为白色,这将增加分析图像的困难。

    纠错等级的编码如下图 6.10 的表格所示:



    图6.10 纠错等级编码

    关于蒙版图案的生成,在后文 6.7 中具体说明。格式信息的示例如下:

    假设存在纠错等级为 M(对应 00),蒙版图案对应 000,5bits 的数据位为 00101,10bits 的纠错位为 0011011100
    则生成了在异或操作之前的 bits 序列为:001010011011100
    101010000010010 做异或 XOR 操作,即得到最终格式信息:100000011001110

    6.5 版本信息 (Version Information)

    对于 Version 7 及其以上的二维码,需要加入版本信息。如下图 6.11 蓝色部分所示:



    图6.11 版本信息

    版本信息依附在定位图案周围,故大小固定为 18bits。水平竖直方向的填充方式如下图 6.12 所示:



    图6.12 版本信息填充方式

    18bits 的版本信息中,前 6bits 为版本号 (Version Number),后 12bits 为纠错码 (BCH Bits)。示例如下:

    假设存在一个 Version 为 7 的二维码(对应 6bits 版本号为 000111),其纠错码为 110010010100;
    则版本信息图案中的应填充的数据为:000111110010010100

    6.6 数据码与纠错码

    此后即可填充第五章得到的数据内容了。填充的思想如下图 6.13 的 Version 3 二维码所示,从二维码的右下角开始,沿着红线进行填充,遇到非数据区域,则绕开或跳过。



    图6.13 二维码数据填充(原始版)

    然而这样难以理解,我们可以将其分为许多小模块,然后将许多小模块串连在一起,如下图 6.14 所示(截取自 QR Code Spec 的图 15):



    图6.14 二维码数据填充

    小模块可以分为常规模块和非常规模块,每个模块的容量都为 8。常规情况下,小模块都为宽度为 2 的竖直小矩阵,按照方向将 8bits 的码字填充在内。非常规情况下,模块会产生变形。
    填充方式上图 6.14,图中深色区域(如 D1 区域)填充数据码,白色区域(如 E15 区域)填充纠错码。遍历顺序依旧从最右下角的 D1 区域开始,按照蛇形方向(D1→D2→…→D28→E1→E2→…→E16→剩余码)进行小模块的填充,并从右向左交替着上下移动。下面给出若干填充原则:

    原则 1:无论数据的填充方向是向上还是向下,常规模块(即 8bits 数据全在两列内)的排列顺序应是从右向左,如下图 6.15所示;



    图6.15 常规模块内的填充方向

    原则 2:每个码字的最高有效位(即第7个bit)应置于第一个可用位。对于向上填充的方向,最高有效位应该占据模块的右下角;向下填充的方向,最高有效位占据模块的右上方。
    注:对于某些模块(以下图 6.17 为例),如果前一个模块在右边模块的列内部结束,则该模块成为不规则模块,且与常规模块相比,原本填充方向向上时,最高位应该在右上角,此时则变为左下角;
    原则 3:当一个模块的两列同时遇到对齐图案或时序图案的水平边界时,它将继续在图案的上方或下方延续;
    原则 4:当模块到达区域的上下边界(包括二维码的上下边界、格式信息、版本信息或分隔符)时,码字中任何剩余 bits 将填充在左边的下一列中,且填充方向反转;如下图 6.16 中的两个模块遇到了二维码的上边界,则方向发生变化;



    图6.16 非常规模块填充方向的改变(举例于 QR Code Spec 图 13)

    原则 5:当模块的右一列遇到对齐图案,或遇到被版本信息占据的区域时,数据位会沿着对齐图案或版本信息旁边的一列继续填充,并形成一个不规则模块。如果当前模块填充结束之前,下一个的两列都可用,则下一个码字的最高有效位应该放在单列中,如下图 6.17 所示:



    图6.17 模块单列填充

    6.7 蒙版图案

    按照上述思路即可将二维码填充完毕。但是那些点并不均衡,如果出现了大面积的空白或黑块,扫描识别会十分困难,所以按照在前文 6.4 中格式信息的处理思路,对整个图像与蒙版进行蒙版操作(Masking),蒙版操作即为异或 XOR 操作。
    二维码又 8 种蒙版可以使用,如下图 6.18 所示,公式也在图中说明。蒙版只会和数据区进行异或操作,不会影响与格式信息相关的功能区。
    注:选择一个合适的蒙版也是有一定算法的。

    蒙版图案如下图 6.18 所示,对应的产生公式与蒙版 ID 如下图 6.19 的表格所示:



    图6.18 蒙版图案



    图6.19 蒙版图案产生公式

    蒙版操作的过程与对比图如下图 6.20 所示,图中最上层是没有经过蒙版操作的原始二维码,其中存在大量黑色区域,难以后续的分析识别。经过两种不同蒙版的处理,可以看到最后生成的二维码变的更加混乱,容易识别。



    图6.20 蒙版操作示例

    蒙版操作之后,得到的二维码即为最终我们平常看到的结果。

    七. 源码

    笔者原本准备用 C++ 与 OpenCV 写一个二维码解析程序,现在学了二维码的原理后,发现好难。另外网上关于二维码解析与生成的程序基本都是用 Python 写的,笔者又想找个合适机会学习一下 Python,所以这段时间就准备从二维码入手,学习一下 Python 的基础~

    源码及解析笔者会随学习的进度持续更新~

    八. 后记

    笔者学习完毕二维码内容后不禁感叹,二维码规则的制定当真是凝聚了多少研究者的心血。学无止境,在知识的海洋中,当真是需要抱着敬畏之心和谦卑的态度,才能体会到这片海洋的浩瀚。
    研究二维码的过程十分有趣,学到了不少东西,后续过程中笔者会持续更新对二维码的学习心得体会~

    展开全文
  • 聚合支付二维码生成原理

    千次阅读 2020-06-08 22:38:03
    聚合支付二维码生成原理 聚合支付平台提供平台支付URL,生成统一的支付二维码。当消费者根据二维码扫描时,聚合支付平台根据扫描者浏览器类型判断支付类型,并提交参数给聚合支付平台支付处理接口处理。平台支付处理...

    聚合支付二维码生成原理

    聚合支付平台提供平台支付URL,生成统一的支付二维码。当消费者根据二维码扫描时,聚合支付平台根据扫描者浏览器类型判断支付类型,并提交参数给聚合支付平台支付处理接口处理。平台支付处理接口根据支付类型和商户ID,调用相应的支付渠道支付接口进行支付处理

    在这里插入图片描述

    1.商户分别开通微信、支付宝、京东金融等支付渠道,各个平台审核通过后会生成微信商户编码,支付宝商户编码和京东金融商户编码
    2.商户将这些渠道的支付账号配置到聚合平台中,并分配给用户一个聚合唯一用户标识ID
    3.聚合平台通过微信、支付宝和京东金融第三方API调用形成具体支付过程(这个过程商户不用关注),当其他消费者扫描带有用户标识的聚合平台URL时,根据扫描者手机使用的内置UAG判断是哪个支付平台,前端获取到后把商户标识和支付方式传递给聚合支付平台的支付API,
    4.聚合平台的支付API根据参数生成相应的平台支付订单
    5.消费者确认支付完成
    6.商户定期在聚合支付后台提现金额到对应账号即可。

    简单的 demo

    扫描二维码本质上就是通过扫描得到一个网址,所以,我们要写一个页面。
    支付宝的链接可以通过 js 直接跳转;微信的不能直接跳转到支付,只能通过微信的扫描接口唤起支付模块,所以变通一下,让微信的链接变成微信的支付二维码,再扫描一次。

    其实,像美团的二维码是可以直接跳转到微信的支付模块的,并不用扫描第二次,笔者尝试了很多方法仍然不能直接跳转,推测是美团和微信有相关协议让他们可以直接跳转,如果有了解的读者能赐教一二将不胜感激。

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" />
        <title>jasonPayTestDemo</title>
    </head>
    <body>
    
    <!-- 隐藏微信支付的二维码,可以是个的也可以是企业的,如果做统一聚合一般都是做企业的,支付成功到企业账户后再转给个人用户或者个人用户使用提现再转到其个人微信或者其他账户中去 -->
    <div class="container" id="wechat" style="display: none;">
       <div style="text-align: center;">
           <img src="http://qr.liantu.com/api.php?text=wxp://f2f0lGxS0y-AT4xJ9IIXI_nKcp3U2b2b_W0L">
           <h3>please use wechat, long presh and pay</h3>
       </div>
    </div>
    </body>
    </html>
    <script language="javascript">
    
        var ua = navigator.userAgent.toLowerCase();
        if(ua.match(/MicroMessenger/i)=="micromessenger") {
            goAndPayByWechat();
        } else if(ua.match(/AlipayClient/i)=="alipayclient"){
            goAndPayByAli();
        } else{
            alert("please use wechat or alipay");
        }
    
        function goAndPayByAli(){
             window.location.href="HTTPS://QR.ALIPAY.COM/FKX09508CLUZB0JA2UHC36";
        }
    
        function goAndPayByWechat(){
            document.getElementById("wechat").removeAttribute("style");
        }
    </script>
    

    参考资料

    作者:Jason_M_Ho
    链接:https://www.jianshu.com/p/ec23449820ba

    展开全文
  • 目录 1 引入 ...5 QR code二维码生成流程及原理 5.1 数据编码 5.2 纠错码 5.3 最终编码 5.4 画二维码 5.5 二维码优势 6 个性二维码 7 总结 1 引入 近年来,随着移动互联网的发展,二维...

    目录

    1 引入

    2 历史

    2.1 一维码

    2.2 二维码

    3 分类

    3.1 线性堆叠式二维码

    3.2 矩阵式二维码

    3.3 邮政码

    4 QR code二维码结构

    5 QR code二维码生成流程及原理

    5.1 数据编码

    5.2 纠错码

    5.3 最终编码

    5.4 画二维码

    5.5 二维码优势

    6 个性二维码

    7 总结


    1 引入

    近年来,随着移动互联网的发展,二维码也开始被广泛应用,尤其是其与电子商务的紧密结合,使二维码成为一个当下很火的概念。随着国家信息化进程的不断推进,物联网应用发展的高歌猛进,我国二维码行业也呈现出百家争鸣的趋势,涉足二维码应用的商家越来越多,可谓是万“码”奔腾。

    2 历史

    首先我们简单了解下二维码的发展历史。

    2.1 一维码

    谈到二维码就不得不涉及一维码,上个世界 60 年代至 70 年代,条形码联合发明人诺曼・约瑟夫・伍德兰德(Norman Joseph Woodland)发明了一维码(条形码),该技术的诞生几乎改变了全球的商业活动形式,使得收银员的工作效率变得更高效,顾客也可以节省更多时间。不过初代的条形码采用的还是还是环形设计,想要完成扫描还需要格外安装一部 500 瓦特发光体的巨型扫描仪吗,非常厚重但是节省了不少的劳动力。

    2.2 二维码

    根据市场的需求一维码(条形码)用的越来越多,但是其缺点也展现出来。我们生活中使用过的一维码场景最多的就是商品扫码或者快递码,为什么会在这些场景下呢,因为只有这些需求是一串字母或数字。所以一维码的数据容量较小(30 个字符左右)、只能包含字母和数字、尺寸相对较大(空间利用率较低)、遭到损坏后便不能阅读的缺点暴露出来。为了弥补这些缺陷,这个时候人们开始寻找更佳的代替方案。

    1994 年,日本电装公司正式宣布公开首个 QR Code,而 QR 的全称就是“Quick Response”,翻译过来就是快速响应,二维码相比一维码(条形码)确实具有数据容量更大、超越了字母数字的限制、尺寸小、具有抗损毁能力等优势,逐渐的中国物品编码中心根据市场需要制定了两个二维码的国家标准,2016年8月3日,支付清算协会向支付机构下发《条码支付业务规范》,中国的移动支付如支付宝、微信等应用场景遍地开花。

    3 分类

    二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的、黑白相间的、记录数据符号信息的图形,主要有三类分别是线性堆叠式二维码、矩阵式二维码、邮政码。

    3.1 线性堆叠式二维码

    是在一维条码编码原理的基础上,将多个一维码在纵向堆叠而产生的。典型的码制如:Code16K、Code 49、PDF417等。

    1583307477502

    3.2 矩阵式二维码

    是在一个矩形空间通过黑、白像素在矩阵中的不同分布进行编码。典型的码制如:Aztec、Maxi、Code、QRCode(也是此次文章分享内容)、Data、Matrix等。

    1583307501566

    3.3 邮政码

    通过不同长度的条进行编码,主要用于邮件编码,如:Postnet 、 BPO4-State 。

    1583307534993

    4 QR code二维码结构

    知道了二维码由来和分类,我们就逐渐去看看到底是怎么生成的,这里选择了市场上流行的、又有丰富的参考文档的QR code二维码。

    QR code二维码整体分为功能区编码区,功能区主要用于定位,编码区则是真正存储数据的。

    有两个地方需要注意:

    • 一是二维码所有的模块中,储存的并不都是我们需要的信息,甚至只有一小部分才是。在上面的图中,只有数据和纠错码字中的数据才是我们实际想存储的数据。
    • 二是版本信息:二维码一共有40个版本,不同版本的区别主要是存储数据的模块的多少(每一块黑/白块就是一个模块),模块数量遵循: moduleCount = 21 + (n-1)×4,比如:版本1的模块数量是21*21,版本40的模块数量为: 21 + (40-1)×4 = 177。

    1583308306323

    那么这些块都代表什么意思呢?其中功能图形包括位置探测图形、位置探测分隔符、定位图形、校正图形四大块,编码区包括格式信息、版本信息、数据和纠错码字三大块。具体定义如下:

    【位置探测图形】三个就可以标识一个矩形了

    【位置探测分隔符】每个探测图形和编码区域之间有一条1单位宽度的分隔符.由白色块组成

    二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了

    【定位图形】黑白色相间交替组成的一行一列两条位于横纵的两两探测图形之间,用于确定符号的密度和版本,提供决定模块坐标的基准位置

    【校正图形】类似小号的探测图形,中心矩形边框变为1单位,这种校正图形的数量由version来定,大于version 1的都有该校正图形.

    【格式信息】表示该二维码的纠错级别,分为L、M、Q、H;

    【版本信息】即二维码的规格,QR码符号共有40种规格的矩阵(一般为黑白色),从21x21(版本1),到177x177(版本40),每一版本符号比前一版本 每边增加4个模块。

    【数据和纠错码字】使用黑白的二进制网格编码内容。8个格子可以编码一个字节。数据是我们需要的信息,纠错码字用于修正二维码损坏带来的错误。

    5 QR code二维码生成流程及原理

    二维码生成流程主要分为四步,首先我们将所需要展示的数据进行数据编码,其次对于数据编码后的数据码利用里德-所罗门算法计算其纠错码,然后将数据码和纠错码合并到一起形成的就是最终编码,最后利用二维码结构进行画二维码流程,即先对功能图形进行放置,在对格式、版本信息、数据进行放置,最后对于得到的二维码进行掩码计算获取最终可以投入使用的二维码。大体流程如下图:

    1583310553393

    接下来就依照上面的流程进行详细的介绍。

    5.1 数据编码

    这里的数据编码指的是对于二维码中所需要展示的数据进行编码,为了得到一串0和1形成的数据填入我们的二维码格子,其编码过程如下流程图所示。首先对所要展示的数据进行数据编码,然后根据编码数添加结束符,最后利用得到的数据串进行按8bits重排,最后根据纠错等级添加补齐符得到我们需要的数据码。

    1583310613746

    5.1.1 数据编码

    数据编码顾名思义就是对于我们所需要展示的数据进行编码,分为数字编码(Numeric mode)、字符编码(Alphanumeric mode)、字节编码(Byte mode)、日文编码(Kanji mode)等等。本章节主要为大家介绍数据编码(Numeric mode)、字符编码(Alphanumeric mode)两种常用编码方式。

    数字编码

    数字编码(Numeric mode)包含从0到9。如果需要编码的数字的个数不是3的倍数,那么,最后剩下的1或2位数会被转成4或7bits,则其它的每3位数字会被编成 10,12,14bits,编成多长还要看二维码的尺寸(下面有一个表Table 3说明了这点)

    1586259492992

    具体实现我们来看这个例子:

    在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

    注意:

    • 这里的三位数字被转成10位的原因是由于根据table3中版本 1 所对应的数字编码位数。
    • 数字编码的标志如下图所示,数字编码为0001,字符编码为0010。

    1586259831930

    字符编码

    字符编码(Alphanumeric mode)包括0-9,大写的A到Z(没有小写),以及符号$ % * + – . / : 包括空格。这些字符会映射成一个字符索引表。如下所示:(其中的SP是空格,Char是字符,Value是其索引值)编码的过程是把字符两两分组,然后转成下表的45进制,然后转成11bits的二进制,如果最后有一个落单的,那就转成6bits的二进制。

    1586260008458

    在Version 1的尺寸下,纠错级别为H的情况下,编码: AC-42

    1. 从字符索引表中找到 AC-42 这五个字条的索引 (10,12,41,4,2)

    2. 两两分组: (10,12) (41,4) (2)

    3. 把每一组转成11bits的二进制:

      (10,12) 的45进制为 10 * 45+12,等于 462 转成 00111001110

      (41,4) 的45进制为41 * 45+4, 等于 1849 转成 11100111001

      (2) 等于 2 转成 000010

    4. 把这些二进制连接起来:00111001110 11100111001 000010

    5. 把字符的个数转成二进制 (Version 1-H为9 bits ): 5个字符,5转成 000000101

    6. 在头上加上编码标识 0010 和第5步的个数编码: 0010 000000101 00111001110 11100111001 000010

    注意:

    • 第5步中 (Version 1-H为9 bits ) 这个依据table3中Version 1所对应的字符编码位数。
    • 第6步中编码标识 0010如下图所示,数字编码为0001,字符编码为0010。

    5.1.2 结束符

    假如我们有个HELLO WORLD的字符串要编码,根据字符编码结果,我们可以得到下面的编码

    1586260972577

    加上结束符:

    1586260988251

    5.1.3 按8bits重排

    如果所有的编码加起来不是8个倍数我们还要在后面加上足够的0,比如上面一共有78个bits,所以,我们还要加上2个0,然后按8个bits分好组:

    1586261034916

    5.1.4 补齐码

    由于关于每一个Version的每一种纠错级别的最大Bits限制,所以如果还没有达到我们最大的bits数的限制,我们还要加一些补齐码(Padding Bytes),Padding Bytes就是重复下面的两个bytes:11101100 00010001 。

    假设我们需要编码的是Version 1的Q纠错级,那么,其最大需要104个bits,而我们上面只有80个bits,所以,还需要补24个bits,也就是需要3个Padding Bytes,我们就添加三个,于是得到下面的编码:

    1586260914772

    5.2 纠错码

    纠错码目的是如果我们的数据依据所罗门算法进行处理得到与数据码相对应的纠错码,上面我们提到了纠错级别,二维码中有四种级别的纠错(从低到高为L、M、Q、H),这就是为什么有人在二维码的中心位置加入图标,也依旧能够扫描(就是二维码残缺量不超过所对应的纠错等级能允许的范围时,使用扫描工具依旧能扫描出内容的原因)。

    1586311555144

    其具体流程为对于我们所要展示的数据进行分组,按组在进行分块,根据得到的数据块依次进行(Reed-Solomon error correction) 里德-所罗门纠错算法处理,最后每个块都得到了相应的纠错码。相应流程图如下所示。

    1583310653842

    5.2.1 数据分组

    我们需要对数据码进行分组,也就是分成不同的Block,然后对各个Block进行纠错编码,对于如何分组,我们可以查看定义表。

    1586311639420

    注意:

    • Number of Error Code Correction Blocks :需要分多少个块。
    • Error Correction Code Per Blocks:每一个块中的code个数,所谓的code的个数,也就是有多少个8bits的字节。
    • 上图左侧依次是版本号、纠错等级、需要的组和blocks,(c、k、r)表示每个组的总数据个数、每个块的数据码个数、每个块的纠错码个数为2*r。

    那么具体我们来看一下实例:

    上述的Version 5 + Q纠错级:需要4个Blocks(2个Blocks为一组,共两组),头一组的两个Blocks中各15个bits数据 + 各 9个bits的纠错码(注:表中的codewords就是一个8bits的byte)(再注:最后一例中的(c, k, r )的公式为:c = k + 2 * r)

    根据上述表中我们可以看出,在Version 5 + Q纠错级时数据需要分为2个组,每个组拥有2个block,每个block拥有15个数据,2*9=18个纠错码。

    5.2.2 里德-所罗门纠错算法

    事实上,尽管纠错码在数学上似乎令人生畏。但是数学独创性的复杂性也掩盖了它相当直观的目标和机制,这里我们也是可以明白其大概纠错机制的。

    纠错码可能看起来像一个挺难的数学概念,但实际上它们是基于一个巧妙的数学实现的直观理念:让我们使数据结构化,以便我们可以在数据损坏时,通过“修复”结构,“猜测”损坏的数据是什么。在数学上,我们使用伽罗瓦域的多项式来实现这个结构,这就是为什么所罗门算法涉及很多多项式计算。

    举一个更实用的比喻:

    假设您想要将消息传递给其他人,但这些消息可能会一路被破坏。纠错码的主要观点是,我们可以使用一小组仔细选择的单词,即“缩小字典”,而不是使用整个字典词典,以便每个字词与其他字词不同。这样,当我们收到一条消息时,我们只需要在缩小的字典内查找1)检测哪些字被损坏(因为它们不在我们缩小的字典中); 2)通过查找我们词典中最相似的单词来纠正被破坏的单词。

    看起来也云里雾里,那么我们再来看下面这个例子:

        t h i s
        t h a t
        c o r n

    添加一组独特的字符,以便在任何新增位置都没有重复的字符,并添加一个单词来帮助解释:

        t h i s a b c d
        t h a t b c d e
        c o r n c d e f
        t h i n d e f g

    请注意,此字典中的每个单词与其他单词至少有5个字符不同,因此距离为5。这允许在已知位置最多有4个错误,这些错误称为丢失,或者在未知位置中的2个错误需要纠正。

    假设发生4次错误:

       t * * * a b * d

    然后可以在字典中搜索4个未丢失的字符,并找到与这4个字符匹配的唯一条目,因为距离为5。

    假设在这些模式之一中有两个错误发生:

      t h i x a x c d
      x h i x a b c d
      t h x x a b c d

    这里的问题是错误的位置是未知的。8个中取6个字符的可能子集有28个,因此使用有这6个字符的28个子集中的每个子集进行搜索,因为距离为5,将只有一个匹配6个字符的子集(假设发生2个或更少的错误)。

    通过这些示例,你可以看到数据冗余在恢复丢失信息中的优势:冗余字符可帮助你恢复原始数据。前面的例子显示了粗略的错误纠正方案是如何工作的。Reed-Solomon的核心思想是相似的,将冗余数据附加到基于伽罗华域数学的消息上。原始纠错解码器与上述错误示例类似,搜索与有效消息相对应的接收消息的子集,并选择匹配最多的消息作为纠正的消息。

    如果一个单词在通信中被破坏了,这没什么大不了的,因为我们可以通过查看字典并找到最接近的单词来很容易地修复它,这可能是正确的(但是如果输入消息太严重损坏,则有可能选择错误,但概率非常小)。而且,我们的单词越长,它们就越可分离,因为更多的字符可以被破坏而不受任何影响。

    所以每个block的纠错码计算主要是通过上述说到的里德-所罗门纠错算法(Reed-Solomon error correction)来实现的。对于这个算法,里面有很多的数学计算涉及到多项式,还有不理解的同学直接认为它就像一种加密算法,把数据码经过一系列神操作变成了另外一堆个数都给你规定好的数据码。

    5.2.3 获取纠错码

    在利用里德 - 所罗门算法得到了各个块的纠错码后,具体数据如下图所示。一个version5-Q的示例(可以看到每一块的纠错码有18个codewords,也就是18个8bits的二进制数)

    1586311958780

    5.3 最终编码

    得到纠错码后这个时候如果你以为我们可以开始画图,你就错了。我们要想填进去的数据是得到一串数据,而不是分成好多块,所以这时候就到了要把数据码和纠错码的各个codewords交替放在一起变成一串数据。

    其流程如下图所示。将数据码和纠错码分别按块排列,按列取出,然后进行合并,并添加相应的remainder构成最终编码。

    1583310684083

    流程看起来挺简单的,但是到了具体实例怎么操作呢?

    5.3.1 数据码按块排列、按列取出

    1586343337132

    对于数据码:把每个块的第一个codewords先拿出来按顺度排列好,先取第一组的第一块的第一个,然后再取第一组的第二块的第二个,如此类推。

    1586343201846

    上述示例中的Data Codewords如下:

    1. 先取块1的第一列:67, 246, 182, 70
    2. 然后再取块2的第一列:67, 246, 182, 70, 85,246,230 ,247
    3. 如此类推:67, 246, 182, 70, 85,246,230 ,247 ……… ……… ,38,6,50,17,7,236

    5.3.2 纠错码按块排列、按列取出

    1586343367977

    和数据码取的一样。

    1586343144375

    如下:

    1. 先取块1的第一列:213,87,148,235
    2. 然后再取块2的第一列:213,87,148,235, 199,204,116,159
    3. 如此类推:213,87,148,235,199,204,116,159,…… …… 39,133,141,236

    5.3.3 数据码和纠错码合并

    由以上数据码和纠错码分别按块排列、按列取出得到下述结果,

    数据码:67, 246, 182, 70, 85,246,230 ,247 ………  ……… ,38,6,50,17,7,236
    
    纠错码:213,87,148,235,199,204,116,159,…… …… 39,133,141,236

    这两组放在一起(纠错码放在数据码之后)得到:

    67, 246, 182, 70, 85, 246, 230, 247, 70, 66, 247, 118, 134, 7, 119, 86, 87, 118, 50, 194, 38, 134, 7, 6, 85, 242, 118, 151, 194, 7, 134, 50, 119, 38, 87, 16, 50, 86, 38, 236, 6, 22, 82, 17, 18, 198, 6, 236, 6, 199, 134, 17, 103, 146, 151, 236, 38, 6, 50, 17, 7, 236, 213, 87, 148, 235, 199, 204, 116, 159, 11, 96, 177, 5, 45, 60, 212, 173, 115, 202, 76, 24, 247, 182, 133, 147, 241, 124, 75, 59, 223, 157, 242, 33, 229, 200, 238, 106, 248, 134, 76, 40, 154, 27, 195, 255, 117, 129, 230, 172, 154, 209, 189, 82, 111, 17, 10, 2, 86, 163, 108, 131, 161, 163, 240, 32, 111, 120, 192, 178, 39, 133, 141, 236

    这就是我们的数据区,终于获取到整体数据了,开心~

    5.3.4 添加补齐符

    QR 码各版本符号所包含的数据和纠错块通常正好填满符号的码字容量,而在某些版本中,也许需要3、4 或7 个剩余位,添加在最终的信息位流中以正好填满编码区域的模块数,具体参照我们的表1 。

    1586342418207

    上述的5Q版的二维码,参照定义表还要加上7个bits,所以在最终编码的后面加零就好了。

    5.4 画二维码

    1586345057297

    终于到了万众期待的一步!最终编码有了那么可以画二维码了,画二维码肯定也有流程,二维码结构如上图所示,就像我们第一部分提到的各个位置放置不同的模块,但整体分为功能区和数据区放置。首先需要对功能区放置,其次放置最终编码,最后进行掩码处理。接下来让我们一步步感受一下如何画一个二维码。

    5.4.1 位置探测图形

    位置探测图画在三个角上,并且大小是固定的,外边宽为7,中间宽位5,内边宽为3 。

    1586345563550

    5.4.2 位置探测分隔符

    在每个位置探测图形和编码区域之间有宽度为1个模块的分隔符。

    5.4.3 校正图形

    校正图形的数量视符号的版本号而定,大小是固定的,外边宽为5,内边宽为3 。如下表所示如果时v8版本那么就有6个校正图形。

    1586345798219

    1586345807140

    5.4.4 定位图形

    定位图形是水平和垂直定位图形,分别为一个模块宽的一行和一列,由深色浅色模块交替组成,其开始和结尾都是深色模块。version8版本时定位图形行和列穿过2个校正图形。

    1586345788884

    5.4.5 格式信息

    格式信息为15位,其中有5个数据位,10个是用BCH(15,5)编码计算得到的纠错位。BCH(15,5)一共15位,数据占5位,纠错码10位。

    • 5个数据bits:其中,2个bits用于表示纠错等级, 3个bits表示使用的掩码。
    • 10个纠错bits:主要通过BCH Code来计算。

    1586346036083

    我们来看个例子:

    1586346245164

    各个数据获取来源为:

    掩膜图形参考:8个掩膜图形选第5个,二进制为101 (掩模图形我们在后面介绍)
    
    数据: 纠错等级 + 掩模图形
    
    BCH位: 由BCH Code来计算
    
    掩膜前的位序列:数据 + BCH位
    
    用于XOR操作的掩模图形:掩模图形参考的掩模获取
    
    格式信息模块图形: 与掩模图形做XOR操作。其中XOR操作为如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。(因为我们选用了00的纠错级别和000的Mask,从而造成全部为白色,这会增加我们的扫描器的图像识别的困难,白色越多扫码越困难)

    下图可以看到15位的格式信息放置了两遍,出现两次以提供冗余,因为它的正确译码对整个符号的译码至关重要。

    1586346666098

    5.4.6 版本信息

    版本信息为18 位,其中,6 位数据位即版本号,12个纠错位通过BCH(18,6)编码计算,将数据位和纠错位合起来就是版本信息。

    举个例子:

    1586346839582

    放置在二维码的左下角和右上角,出现两次以提供冗余,与格式信息一样它的正确译码对整个符号的译码也至关重要。

    1586346856054

    具体每一位放置顺序如下图。

    1586346885156

    5.4.7 数据和纠错码字

    数据和纠错码字的填写也就是我们的上面得到的最终编码的填写,最终编码的填充方式从左下角开始沿着红线填我们的各个bits,1是黑色,0是白色。如果遇到了上面的非数据区,则绕开或跳过。如下图所示。

    1586346913982

    5.4.8 掩码图案

    这个阶段时,整个二维码其实已经绘制完成。但是如果只是按照实际的信息来绘制,可能会导致页面上有一大片黑色或者一大片白色,导致扫码时识别困难如下面的左图。所以这一步需要从QR code提供的掩码模板中选一个来和二维码图形做异或操作,生成均匀的黑白交叉的图形如下面的右图。

    1586347005665

    QR有8个掩码图案你可以使用,如下所示。其中,各个掩码图案的公式生成的结果与原始二维码图做XOR操作。掩码图案只和数据区进行XOR,所以不会影响功能区。

    1586347017078

    掩码图案并不是都可以符合当前数据,根据特征衡量权值,找到最适合的掩码方式。QR code标准提供的筛选特征:

    1. 行/列中相临的模块的颜色相同次数
    2. 颜色相同的模块尺寸
    3. 在行/纵列中出现深浅深浅深图形
    4. 整个符号中深色模块的比率

    1586347064803

    对于原有二维码进行掩码操作过后的二维码就成最终的图了,这个时候我们得到了最终的黑白块均匀的二维码。

    5.5 二维码优势

    从以上二维码生成过程中不难看出其优点

    1. 高密度编码,信息容量大。(40个版本,每个版本存储的数据量不同)
    2. 编码范围广: 该条码可以把图片、声音、文字、签字、指纹等可以数字化的信息进行编码,用条码表示出来;可以表示多种语言文字;可表示图像数据。(分为数字编码、字符编码、字节编码(Byte mode)、日文编码等等,涵盖了日常生活中需要的)
    3. 容错能力强,具有纠错功能。这使得二维条码因穿孔、污损等引起局部损坏时,照样可以正确得到识读。(四种纠错等级,最高损毁面积达30%仍可恢复信息)。
    4. 成本低,易制作,持久耐用。

    6 个性二维码

    这里为什么要介绍个性二维码,正是因为我们通过上面熟悉了其生成流程和原理,才能明白个性二维码的独特性来源于其具有较强的纠错能力!即使二维码部分被覆盖或丢失,依旧能识别出记录的完整信息,其制作思路中心替换法、色彩缤纷法、局部遮挡法、整体造型、出现在不该出现的位置等等,这使得创新设计成为可能。

    1586348391722

    7 总结

    文章首先从二维码怎么从一维码一步步衍生而来,市面上二维码的分类这两部分让我们对二维码有个简单的认识。其次选择了我们生活中最常用的QR code二维码,对于其结构的功能区和数据区做大致介绍。然后对于QR code二维码生成过程中数据码、纠错码、最终编码原理知识进行详细说明,最后从功能区图形的放置、数据区数据的填入、掩码处理对画二维码的流程进行梳理。

    也提到了二维码在冗余这个方面的处理,在日常开发中我们讲究去除冗余,但二维码中根据里德-所罗门算法得到的纠错码其实是包含了很多冗余数据的,而这些冗余数据又恰恰是我们能在二维码破坏的情况下能扫出来的原因,也让我们生活中多了形形色色的二维码;画二维码过程中编码格式、信息格式的放置两次也感觉冗余,但是这样才能防止版本、格式重要信息的丢失。所以不同场景下是否需要冗余,以及不同的冗余的方式又起到不一样的作用。

    希望通过本篇文章让大家了解到日常生活中的二维码不仅仅是黑白块的组合,而是通过各种明确的规格标准、复杂的编码方式、深奥的数学理论得来,包含了非常值得我们探究的逻辑与知识。

    欢迎大家指出有问题的地方,一起进步。

    参考:

    https://www.cnblogs.com/swordc007/p/9151205.html

    https://www.freebuf.com/geek/204516.html

    https://www.cnblogs.com/jin20000/p/3424966.html

    https://juejin.im/post/58eb05ffb123db1ad06615c9#heading-11

    https://coolshell.cn/articles/10590.html

    展开全文
  • 是java后台的二维码生成以及扫一扫解析二维码原理的实例,包含二维码生产,以及解析原理,代码实现不易。
  • 小知识:浅谈二维码生成和识别原理

    万次阅读 多人点赞 2019-12-26 15:14:15
    二进制生成图形码 二维码的定位 前言 不知不觉中,我们的生活到处充满了二维码。登录账户需要二维码;加好友需要二维码;共享单车需要二维码;商品包装上也有二维码;甚至连楼下卖水果的阿姨手里都拿张二维码...
  • 二维码生成原理

    千次阅读 2017-10-19 10:47:07
    二维码的基础原理是什么? 二维条码是指在一维条码的基础上扩展出另一维具有可读性的条码,使用黑白矩形图案表示二进制数据,被设备扫描后可获取其中所包含的信息。一维条码的宽度记载着数据,而其长度没有记载数据...
  • canvas生成二维码生成

    2018-09-12 17:18:22
    canvas生成二维码生成,输入需要的连接就可以生成对应的二维码,这个只是初期的二维码,如果想学习的小伙伴可以下载源码学习,当然也是可以完善的,比如你可以设计成二维码中间加上需要的图片
  • 简单的基于java的二维码生成原理,所用到的知识有输入输出流也就是IO,还有用到关键的一个二维码jar包QRCode.jar,
  • 基础——二维码生成细节和原理

    千次阅读 2018-12-28 17:32:26
    二维码生成细节和原理 二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型:比如:字符,数字,日文,...
  • Android二维码登录原理生成与解析

    千次阅读 2017-09-22 14:06:58
    1.二维码原理   很重要的一部分知识:二维码一共有 40 个尺寸。官方叫版本 Version。Version 1 是 21 x 21 的矩阵,Version 2 是 25 x 25 的矩阵,Version 3 是 29 的尺寸,每增加一个 version,就会增加 4 的...
  • NULL 博文链接:https://tcw290.iteye.com/blog/1831864
  • 转换成boolean二维数组具体原理:1.创建信息对象2.将信息转换为byte数组3.创建图片缓冲对象4.创建画板对象5.创建二维码对象6.对二维码属性进行配置和对图像大小进行配置。7.将信息byte数组用二维码对象calQrcode...
  • 这次分享海报里面的元素比较少,进行绘制的分别有头像,海报背景以及二维码二维码生成请看上面《小程序本地生成二维码》一文),此次没有涉及到文字的绘制,不过原理大致相同,这篇文章就不对文字绘制进行阐述了...
  • 基于stm32的二维码生成程序,里面包含一个二维码生成原理的视屏介绍连接,给有需要的人
  • 二维码原理和制作

    千次阅读 2020-07-25 20:58:22
    什么是二维码 1、二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能够存更多的信息,也能表示更多的数据类型。 2、二维条码/二维码(2-...
  • js生成二维码原理

    2015-07-14 09:53:16
    1.引用相关的js文件:  jquery.qrcode.js,qrcode.js ... 以上就可以生成自己的二维码了,手机扫描就可以跳转到指定的页面或者显示内容。  相关的代码在这:http://download.csdn.net/detail/go_walkin

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,642
精华内容 7,056
关键字:

二维码生成原理