大家都熟知二维码,那么字符串是怎么转换成二维码的呢?原理是啥?

闲云侠鹤


二维码的生成细节和原理

二维码又称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 的正方形。

下面我们看看一个二维码的样例:

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

Kanji mode 这是日文编码,也是双字节编码。同样,也可以用于中文编码。日文和汉字的编码会减去一个值。如:在0X8140 to 0X9FFC中的字符会减去8140,在0XE040到0XEBBF中的字符要减去0XC140,然后把结果前两个16进制位拿出来乘以0XC0,然后再加上后两个16进制位,最后转成13bit的编码。如下图示例:

下面我们看几个示例,

示例一:数字编码

在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

示例二:字符编码

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

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

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

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

(10,12) 10*45+12 等于 462 转成 00111001110(41,4) 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

结束符和补齐符

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

编码字符数HELLO WORLD的编码001000000101101100001011 01111000110 10001011100 10110111000 10011010100 001101

我们还要加上结束符:

编码字符数HELLO WORLD的编码结束001000000101101100001011 01111000110 10001011100 10110111000 10011010100 0011010000按8bits重排

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

00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 01000000

补齐码(Padding Bytes)

最后,如果如果还没有达到我们最大的bits数的限制,我们还要加一些补齐码(Padding Bytes),Padding Bytes就是重复下面的两个bytes:11101100 00010001 (这两个二进制转成十进制是236和17,我也不知道为什么,只知道Spec上是这么写的)关于每一个Version的每一种纠错级别的最大Bits限制,可以参看QR Code Spec的第28页到32页的Table-7一表。

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

00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 01000000 11101100 00010001 11101100

上面的编码就是数据码了,叫Data Codewords,每一个8bits叫一个codeword,我们还要对这些数据码加上纠错信息。

纠错码

上面我们说到了一些纠错级别,Error Correction Code Level,二维码中有四种级别的纠错,这就是为什么二维码有残缺还能扫出来,也就是为什么有人在二维码的中心位置加入图标。

错误修正容量L水平7%的字码可被修正M水平15%的字码可被修正Q水平25%的字码可被修正H水平30%的字码可被修正

那么,QR是怎么对数据码加上纠错码的?首先,我们需要对数据码进行分组,也就是分成不同的Block,然后对各个Block进行纠错编码,对于如何分组,我们可以查看QR Code Spec的第33页到44页的Table-13到Table-22的定义表。注意最后两列:

  • Number of Error Code Correction Blocks :需要分多少个块。
  • Error Correction Code Per Blocks:每一个块中的code个数,所谓的code的个数,也就是有多少个8bits的字节。

下图是根据上述表格中的Version8的一个例子(6,24,42)

Format Information是一个15个bits的信息,每一个bit的位置如下图所示:(注意图中的Dark Module,那是永远出现的)

关于Error Correction Level如下表所示:

Version Information一共是18个bits,其中包括6个bits的版本号以及12个bits的纠错码,下面是一个示例:

数据和数据纠错码

然后是填接我们的最终编码,最终编码的填充方式如下:从左下角开始沿着红线填我们的各个bits,1是黑色,0是白色。如果遇到了上面的非数据区,则绕开或跳过。

掩码图案

这样下来,我们的图就填好了,但是,也许那些点并不均衡,如果出现大面积的空白或黑块,会告诉我们扫描识别的困难。所以,我们还要做Masking操作(靠,还嫌不复杂)QR的Spec中说了,QR有8个Mask你可以使用,如下所示:其中,各个mask的公式在各个图下面。所谓mask,说白了,就是和上面生成的图做XOR操作。Mask只会和数据区进行XOR,不会影响功能区。(

注:选择一个合适的Mask也是有算法的

下面是Mask后的一些样子,我们可以看到被某些Mask XOR了的数据变得比较零散了。

Mask过后的二维码就成最终的图了。

参考:https://www.cnblogs.com/alantu2018/p/8504373.html


嘉靖不上朝


移动互联网时代,二维码在我们身边可以随处可见,手机支付有付款码,公交地铁有乘车码,还有最近出现的健康码。

其实不管是付款码还是乘车码,本质上它们都是二维码,那么二维码到底是什么呢?

二维码是什么?

回想一下我们在超市买东西时结账的流程:首先我们打开付款码,接着收营员扫我们的付款码,然后钱就自动从我们的账户中扣除了。

可以看出,扫码付款的过程就是从二维码到人的一个过程,从二维码所代表的信息中找到我们的账户信息并从中扣款。

那么二维码所代表的信息是什么时候确定的?当然是生成二维码的时候啦!

我们要使用手机支付功能,首先必须注册帐号,此时帐号就代表了我们。打开付款码的时候,系统会将我们的身份信息经过一些计算,最终生成一个二维码并展示给我们。

生成二维码的过程就是将信息转换成二维码的过程,扫码的过程则是将二维码再转换成信息的过程,所以二维码本质上只是信息的一种展示形式而已。

二维码结构分析

虽然二维码看起来是毫无规律的,但其实二维码的生成有着固定的格式。

大小

二维码的大小存在 40 种版本(Version),从Version1(21x21的正方形)到Version40(177x177的正方形),每增加一个 Version,大小都会增加 4。

版本越大二维码就会越大,随之所能表示的数据量也就越大。

结构

二维码呈正方形,通常由黑白小方块组成,二维码的整体结构可以分为定位标记、功能区以及数据区三大部分:

  • 定位标记——在二维码的左上角、右上角、左下角有3个类似“回”字的方形图案,这3个图案是用于二维码的定位标记。正因为有定位标记的存在,所以不管我们以什么角度扫描,二维码总是可以被准确的识别出来。二维码中还存在一些小一点“回”字,它们是用于校正定位的标记,并且只会在Version 2及以上版本的二维码中才会出现。

  • 功能区——功能区分为两部分,即图中红色部分和紫色部分。红色部分存放格式信息,用于表示该二维码的纠错级别(至于纠错级别是什么后面在解释),紫色部分存放版本信息,即该二维码的尺寸大小。

  • 数据区——数据区指的是除去定位标记和功能区的其他部分(图中灰色部分),用于保存二维码实际所表示的信息的数据码以及用于纠错的纠错码。

纠错级别

二维码一般有一定的容错率,所以即使二维码被遮挡住一部分,仍然可以被扫描出来,原理就是在生成二维码的过程中对数据做了冗余处理,冗余程度越高容错率就越高(纠错级别越高),二维码能被遮挡的部分自然也就越多。

二维码的纠错级别从低到高分为L(7%)、M(15%)、Q(25%)、H(30%)4个等级,如果需要在二维码中间加logo,那么我们就应该生成H级别的二维码,但也并不是纠错级别越高越好,级别越高需要冗余的数据就越多,那么生成的二维码的复杂程度也就越高,实际使用过程中我们应该根据需求选择合适的纠错级别。

编码模式

我们都知道计算机只认二进制信息,所以我们需要把字符串中的数字、字母、汉字以及各种字符统一转换成由0和1组成的二进制数字串计算机才能识别,所以生成二维码的过程就是将字符串转换成二进制数字串的过程。

最后生成的二进制数字串对应到二维码上,0对应白色的小方块、1对应黑色小方块,按照8个一组依次填充到数据区就是一个完整的可以被识别的二维码了。

根据源字符串类型,二维码主要支持4种标准化的编码模式,分别为数字编码、字符编码、字节编码以及日文编码,当然也支持其他一些特殊的字符集编码以及混合编码。

每种编码模式对应一个4位的二进制的编码模式指示符:

下面以字符编码举个例子,现在有字符串“HELLO WORLD”

1、模式指示符——根据查表可知HELLO WORLD需要使用字符编码模式,所以它的模式指示符为0010。

2、字符计数指示符——表示源字符串的长度,字符计数指示符必须放在模式指示符之后。

字符计数指示符的计算依赖于二维码的版本以及编码模式:

以版本1为例,字符编码需要9bits,HELLO WORLD长度为11,转为二进制为1011,不足9位,左边补5个0得到最终结果000001011,加上模式指示符目前我们得到的二进制数字串为0010 000001011。

3、对原字符串编码,

将HELLO WORLD两两分组得到(H,E)、 (L,L)、(O, )、(W,O)、(R,L)、(D);

根据索引表找到每个字符对应的值,得到(17,14)、 (21,21)、(24,36)、(32,24)、(27,21)、(13);

将每组数字先转成45进制、再将结果转成长度11的二进制串,长度不足的补0。例如(17,14) 转成45进制为17*45+14=779,再将779转成二进制 1100001011,左边补1个0得到01100001011,如果最后一组是单独一个,则转成6位的二进制串,所以字符串HELLO WORLD经过字符编码之后,再加上前面计算好的模式指示符和字符计数指示符之后最终得到

0010 000001011 01100001011 01111000110 10001011100 10110111000 10011010100 001101。

4、 在确定二维码的版本和纠错级别以后,字符串的编码结果应该是一个固定长度的二进制串,如果我们计算的结果长度不够就需要进行不起操作。

例如确定二维码的版本1和纠错级别Q,则最终二进制串的长度需要达到104位。

在第3步中我们得到的最二进制串的长度为74,所以需要进行补齐操作。首先末尾可以至多追加4个0,接着末尾补齐更多的0直到长度是8的倍数,如追加4个0后长度达到78,要达到8的倍数则还需要补2个0;如果这时候长度还没有达到目标,那就在末尾循环追加固定的二进制码11101100 00010001直到达到目标长度。

最后来看一下HELLO WORLD经过字符编码之后结果

掩码图

源字符串在经过编码之后被转换成二进制的数字串,根据这个二进制数字串画出来的二维码通常会存在黑白色块分布不均的情况,这会导致二维码容易扫描失败。

为了解决这个问题,官方提供了8种掩码方案:

我们需要选择一个掩码图与我们生成的二维码再做一次异或操作,这样黑白色块分布就会更加的均匀。

那应该选择哪个掩码图呢?这里面涉及到的原理就比较复杂了,大概过程就是先将8个掩码图与二维码都分别进行异或操作,再按照某个规则计算出8个结果的均匀程度,最后取其中效果最好的一个。


萌新程序员成长日记


您好,很高兴回答您的问题。

二维码就目前而言已经被广泛应用于手机支付、帐号登录、防伪溯源、信息获取、网站跳转、手机电商等领域。

其实现思路跟一维码,如条形码一致,即将字符串通过特殊编码,使用若干个与二进制相对应的几何形体来表示数字和文字,并通过图像输入设备或光电扫描设备自动识别,以实现信息自动处理还原。

将字符串转化为二维码核心部分是编码,通常市面上的二维码分为两类,一类为堆叠式二维条码,一类是矩阵式二维条码,下面主要讲述一下矩阵式二维条码实现原理:

矩阵式二维码通过在一个矩形空间内,通过黑白像素在矩阵中不同分布进行编码,在矩阵相应元素位置上,用点表示二级制“1”,空白表示二进制“0”,点的排列组合所代表的二维码的意义。



分享到:


相關文章: