非凡微信社群营销服务平台 www.haqsl.com 我们提供【社群管理裂变】【自动建群】【多群转播】【活码系统】【小程序开发】【公众号开发】【各类商城 SAAS】一站式服务,各类功能提供免费体验,满意付款,如您还有其他疑问请您添加企鹅/微信 1003312430 方便咨询哦。
非凡社群助手------微信活码系统演示(客户活码二维码累计扫描量一千万+)
活码系统介绍:
二维码图案不变,内容可随时变更, 极大提高营销效果,基于活码技术,二维码图案更简单,扫码更加容易宣传海报、二维码印刷、商品.群.软文。
让二维码图案更简单,扫码更加容易宣传。
,
2016.7.5 更新:长文多图代码预警,电脑食用效果更佳。
完整版代码已上传 GitHub,后续一些有的没的的代码更新也都在 GitHub 上()
给末端的几个被自动识别的 QR 码做了防自动识别。。顺便也检测一下我们这不怎么高的容错率(7%)。要是再被知乎自动识别了。。。_(:з」∠)_
======================================================================
作为一只程序猿,第一篇文章自然要写 hello world,然则呐,我看你们今天这样热情,只写一句 hello world 就闷声你们又不喜悦。恰好最近实习事情在处置 QR 码,就来薛习一下 QR 码版本的 hello world 吧。
-
前期准备
-
靠山信息
要想实现一个 QR 码天生器,我们首先需要领会什么是 QR 码,QR 码有哪些类型,以及 QR 码是若何事情的。
(Quick Response Code) 是二维码的一种,在正方形二位矩阵内通过是非标识编码二进制位从而编码数据,最早发现用于日本汽车制造业追踪零部件。QR 码现有 40 个尺度版本,4 个微型版本。QR 码的数据编码方式有四种:
- 数字(Numeric):0-9
- 大写字母和数字(alphanumeric):0-9,A-Z,空格,$,%,*,+,-,.,/,:
- 二进制/字节:通过 尺度编码
- 日本汉字/假名:通过 尺度编码
QR 码另有四种容错级别可以选择:
- L(Low):7%的字码可被修正
- M(Medium):15%的字码可被修正
- Q(Quartile):25%的字码可被修正
- H(High):30%的字码可被修正
(Wikipedia: QR code, )
(40+4)×4×4=...... ∑(っ °Д °;)っ
咳。。好,那我们为了读者着想 (←_←),只实现 Version 1-Byte mode-Low error control 的 QR 码天生就好了嗯。。
好我们继续。
现在 QR 码随处可见,人人阅码无数可能也发现了一些纪律:这些 QR 码有大有小、有红有绿,有些另有种种装饰,然则它们总有一些部门看起来十分相似,好比三个角落里总有“回”字形的图样。这就要谈到 QR 码的结构了。
- 结构
除了存储编码的数据,QR 码里还含有一些基本尺度里钦定的图样来辅助扫描软件快速识别和解码。
尺度(ISO/IEC 18004)里是这样说的
(图片泉源:ISO/IEC 18004:
Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
以是说我们做 QR 码啊,照样要凭据 QR 尺度,凭据基本尺度来。我没有任何硬点这些图样的意思,它们都是有自己的作用的,我们一个一个说。
- 功能性图样(function patterns):不介入编码数据的区域。
- 闷声区(quite zone):尺度中划定尺度 QR 码(Ver1-40)周围应有宽 4 个单元、微型 QR 码周围应有宽 2 个单元的区域颜色等效于 QR 码中白色点(light module),其中不能有图样或符号,以保证 QR 码清晰可识别。
- 定位标识(finder pattern):之前提到的“回”字形标识,位于 QR 码的左上,右上和左下角,用于协助扫描软件定位 QR 码并变换坐标系。定位标识可以让 QR 码在随便角度被扫描,这是一维条形码做不到的。
(图片泉源:ISO/IEC 18004: Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
- 分隔符(separator):一单元宽的白色点带,位于每个定位标识和编码区域之间用于区分。
- 准时标识(timing pattern):一单元宽的是非交替点带,由玄色起始和竣事,用于指示标识密度和确定坐标系。
- 校正标识(alignment pattern):只有 Version 2 及以上的 QR 码有校正标识。校正标识用于进一步校正坐标系。校正标识的数目取决于版本。
- 编码区域(encoding region):编码数据的区域。
- 花样信息(format information):存储容错级别和数据掩码,和分外的自身 BCH 容错码,讲到再睁开。
- 版本信息(version information):存储版本信息。
- 数据及容错字码(data and error correction codewords):存储编码方式,现实编码的数据和数据的 RS 容错码。
以上就是 QR 码的通用结构尺度了,再来看一看我们要实现的 Version 1 QR 码的结构:
(图片泉源:ISO/IEC 18004: Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
剖析完了 QR 码的结构,豁然开朗,这器械也不就这么回事嘛,简朴!最先做!(多年以后,当程序猿面临电脑屏幕的时刻,将会回想起不懂事的自己立起 flag 的谁人下昼)
- 流程
利便的是,尺度也划定了将数据编码成 QR 码的流程:
- 数据剖析(data analysis):剖析输入数据,凭据数据决议要使用的 QR 码版本、容错级别和编码模式。低版本的 QR 码无法编码过长的数据,含有非数字字母字符的数据要使用扩展字符编码模式。由于我们只实现 V1-L byte mode QR 码,此步略去。
- 编码数据(data encoding):凭据选择的编码模式,将输入的字符串转换成比特流,插入模式标识码(mode indicator)和终止标识符(terminator),把比特流切分成八比特的字节,加入填充字节来知足尺度的数据字码数要求。
- 盘算容错码(error correction coding):对步骤二发生的比特流盘算容错码,附在比特流之后。高版本的编码方式可能需要将数据流切分成块(block)再划分举行容错码盘算。
- 组织数据(structure final message):凭据结构图把步骤三获得的有容错的数据流切分,准备填充。
- 填充(module placement in matrix):把数据和功能性图样凭据尺度填充到矩阵中。
- 应用数据掩码(data masking):应用尺度中的八个数据掩码来变换编码区域的数据,选择最优的掩码应用。讲到再睁开。
- 填充花样和版本信息(format and version information):盘算花样和版本信息填入矩阵,完成 QR 码。
简朴! ( ̄ε(# ̄)╰╮( ̄▽ ̄///) ↓↓↓
-
代码实战
为(yin)了(wei)可(wo)读(lan)和简朴,我们用 Python 来实现这个简化版 QR 码天生器。为了天生和操作图像,我们需要安装第三方图像处置库 。限于篇幅,本文纰谬 PIL 的使用做过多先容,入门可参见 ,。
由于程序需要处置矩阵,利便起见在这里先界说坐标系统。以矩阵的左上角为原点,原点坐标界说为(0,0),i 轴向右,坐标 i 对应列;j 轴向下,坐标 j 对应行。于是对于图像中的像素(i,j),有矩阵元素 mat [ j ] [ i ] 与之对应。
新建 Python 代码文件 qrcode.py,引入需要的库:
为了头脑简捷,我们自顶向下地构建代码。首先,假设我们已经填充好了一个 QR 码的矩阵 bitmap,我们需要把响应的图像天生出来。这里就有了图像巨细的问题:Version 1 的 QR 码示意为 21×21 的矩阵,直接把这个矩阵当做位图来输出的话,图像只有 21 像素宽。为了获得巨细合适的图像,我们先界说图像巨细,再把每一个像素映射到合适的矩阵元素上。
在 qrcode.py 中添加如下代码:
这个函数吸收三个参数:QR 码矩阵 bitmap,图像宽度 width,保留文件名 filename。
这两行初始化了图像和绘图工具。初始化图像时的参数 '1' 代表天生是非模式图像,'white' 代表图像初始化填充白色。
用图像宽度除以矩阵维度获得尺度化后的像素宽度(QR 码中一个单元对应的像素数)。
遍历图像时,将像素坐标(i,j)尺度化为矩阵坐标 [ i ][ j ]。检查不越界之后,按坐标绘制像素,最后保留图像。
保留代码后,我们测试一下这个函数。在文件目录打开命令行/shell,输入 python 进入 Python REPL。引入 qrcode 然后举行测试。
我们界说了一个矩阵 test,然后挪用 qrcode._genImage 来天生一个 240×240,名为 test.jpg 的图像如下。
我们注意到,原点处对应 (0 + 0) % 2 的像素为黑,由于 0 值对应玄色,1 对应白色。为了明确,在 qrcode.py 中加入如下界说
可见我们的图像天生函数是乐成的,现在只需要填充出 QR 码矩阵就行了。
嗯,玩一会。。_(:з」∠)_
好我们继续。
_genImage 函数吸收 QR 码矩阵作为参数,自顶向下地,我们需要天生这个矩阵。思量到一个 QR 码中有许多稳定的图样(fixed pattern),我们可以预先填充好一个含有这些稳定图样的模板,天生 QR 码矩阵时直接把编码好的数据填充到这个模板里就行了。
在 qrcode.py 中加入模板的界说,待填充:
假设 _ver1 是已经填充好的模板,我们天生 QR 码矩阵需要怎么做呢?凭据前期准备,我们需要编码数据,填充数据,应用掩码,再填充花样信息。于是我们界说这些函数:
_encode 编码数据,_fillData 将这些数据填充到模板中,_mask 应用掩码,_fmtEncode 编码花样信息,_fillInfo 填充花样信息,最后 _genBitmap 把这些函数按尺度串联起来,返回准备好的 QR 码矩阵给 _genImage 来天生 QR 码。
接下来我们凭据流程顺序实现这些函数。
- 编码数据
首先我们要检测输入的数据是否跨越 V1-L byte mode 的最大编码长度 17,若是跨越就抛出异常。在 qrcode.py 最先界说异常:
在 _encode 中加入检测
在编码数据之前,还要凭据尺度的划定加入编码模式前缀和数据字符计数,byte mode 的前缀是 0100,接上八位二进制数代表的数据长度,组成数据前缀。再把数据用 ISO/IEC 8859-1 尺度编码,按八个二进制位分组,接上终止符和 11101100 和 00010001 交替的填充字节,按尺度修剪到 19 字节,完成数据编码。实现 _encode 如下:
在 L 容错品级下,编码了数据我们还需要盘算出七位的(可简朴了,看我和善的眼神 )
里德-所罗门码是 。这意味着一个牢固长度输入的数据将被处置成一个牢固长度的输出数据。在最常用的(255,223)里所码中,223 个里德-所罗门输入符号(每个符号有 8 个 )被编码成 255 个输出符号。
大多数里所错误校正编码流程是成系统的。这意味着输出的码字中有一部门包含着输入数据的原始形式。
符号巨细为 8 位元的里所码迫使码长( )最长为 255 个符号。
尺度的(255,223)里所码可以在每个码字中校正最多 16 个里所符号的错误。由于每个符号事实上是 8 个位元,这意味着这个码可以校正最多 16 个短爆发性错误。里德-所罗门码,犹如 一样,是一种透明码。这代表若是信道符号在行列的某些地方被反转,解码器一样可以事情。解码效果将是原始数据的弥补。然则,里所码在缩短后会失去透明性。在缩短了的码中,“丢失”的比特需要被 0 或者 1 替换,这由数据是否需要补足而决议。(若是符号这时刻反转,替换的 0 需要酿成 1)。于是乎,需要在里所解码前对数据举行强制性的侦测决议(“是”或者“补足”)。
(Wikipedia: 里德-所罗门码,)
......................................(⊙v⊙).....................................
这。。照样留给有兴趣的读者吧(微笑)
参考:
在 _encode 之前加入如下 RS 容错码盘算工具:
(Source: Wikiversity:)
在 _encode 末端直接挪用 _rsEncode 添加容错码,完成数据编码部门。
- 数据切分和填充
(在我完成这个项目之后,想了想数据填充有更优雅的方式,还可以通用在其他版本的 QR 码上。感兴趣或者是想到的读者可以自行实现优化的 _fillData)
QR 码尺度将八个二进制位(一字节)划定为一个数据元组,先将编码后数据的每一个字节填充到 2×4 的矩阵(高版本 QR 码中会泛起不规则形状的字节元组,本文中不思量。)中,再将这些小的矩阵填入 QR 码矩阵。尺度也划定了字节填入小矩阵的方式:
(图片泉源:ISO/IEC 18004: Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
其中,7 代表字节最高位(most significant bit),0 代表最低位(least significant bit)。
在 _fillData 前添加 _fillByte 来实现单个字节的填充:
有了填充好的小矩阵,接下来就把它们填入大矩阵中。尺度划定的填充方式为:由大矩阵的右下最先向上填充,遇到编码区域的界限后向左,改为向下填充,云云蛇行将数据填入数据区域。
(图片泉源:Wikipedia:QR code,)
思量到将小矩阵填入大矩阵的操作会异常频仍,我们把它写成函数来实现复用。在 qrcode.py 最先添加函数
def _matCp(src, dst, top, left):
'''
Copy the content of matrix src into matrix dst.
The top-left corner of src is positioned at (left, top)
in dst.
'''
res = copy.deepcopy(dst)
for j in range(len(src)):
for i in range(len(src[0])):
res[top+j][left+i] = src[j][i]
return res
要实现 _fillData,我们就会用到之前说的模板矩阵,那我们先把模板矩阵填充出来吧。
我们的想法是在模板矩阵中填入在所有 V1-L QR 码中都牢固稳定的标识来简化天生历程,那么首先我们得找出所有这样牢固稳定的标识。之前提到的功能性标识包含了大部门牢固的图样,那么我们先填充出这些功能性标识。定位标识和校正标识可以界说为变量,然则准时标识会随版本转变有长度转变,为了代码的可扩展性,我们把准时标识界说为天生函数。
在 qrcode.py 最先添加界说:
def _transpose(mat):
'''Transpose a matrix'''
res = [[mat[j][i] for j in range(len(mat))] for i in range(len(mat[0]))]
return res
def _timSeq(len, vertical=False):
'''
Generate a horizontal, unless specified vertical
timing sequence with alternating dark and light
pixels with length len.
'''
res = [[i % 2 for i in range(len)]]
if vertical:
res = _transpose(res)
return res
# Finder pattern.
_finder = _matCp(_matCp([[_DARK for i in range(3)] for j in range(3)],
[[_LIGHT for i in range(5)] for j in range(5)], 1, 1),
[[_DARK for i in range(7)] for j in range(7)], 1, 1)
# Alignment pattern. Not used in version 1.
_align = _matCp(_matCp([[_DARK]],
[[_LIGHT for i in range(3)] for j in range(3)], 1, 1),
[[_DARK for i in range(5)] for j in range(5)], 1, 1)
有了这些功能性标识,先别急着往模板里填。仔细读尺度我们会发现,在花样信息区域也有一个牢固稳定的黑点。
(图片泉源:ISO/IEC 18004: Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
现实上这张图里就是 Version 1 QR 码里所有的稳定样式了。继续在 qrcode.py 中填充模板:
我们的模板矩阵就完成了,效果如图:
为了制止填充历程修改模板而导致后续 QR 码天生失足,保险起见我们只通过 deepcopy 使用这个模板,在 qrcode.py 头部加入模块引入:
然后实现 _fillData 如下:
这是一个异常 ad hoc 的实现,代码长然则没有什么技术含量。
测试一下填入数据的效果:
已经有一些 QR 码的样子了! <( ̄︶ ̄)> (没有完成,这是无法扫描的)
- 掩码和责罚
获得了填入数据的矩阵,下一步就是应用掩码来变换数据图样。那有人要问了,既然我们已经把数据编入了 QR 码,想编码的信息就已经在里面了,为什么不直接填入花样信息获得 QR 码,而要多举行这么一步操作呢?
掩码真的是画蛇添足吗?你们呐照样要提高自身的姿势水平。QR 码是要拿来扫描的,而扫描怕的就是无法清晰地分辨出编码信息的每一位。要是 QR 码中是非点数目不均,或是空间漫衍不均都市导致大色块区域的泛起,而大色块区域的泛起会增添扫描时定位的难度,从而降低扫描的效率。更严重的情形下,若是数据填入后恰巧泛起了功能性标识,好比定位标识的图样,还会滋扰正常功能性标识的作用,导致 QR 码无法扫描。
举个栗子:
这样的数据发生的原始 QR 码显著含有大量大面积色块,扫描难度很高。
以是,掩码和之前提到的在数据后添加 11101100 和 00010001 交替的填充字节,都是为了制止这种情形发生,让图像更“平均”。
知道了掩码的重要性,我们来看看掩码到底是什么。在盘算机科学中,掩码就是一个二进制串,通过和数据举行异或运算来变换数据。在 QR 码中,掩码也是通过异或运算来变换数据矩阵。以是你可能已经猜到了,QR 码的掩码就是预先界说好的矩阵。QR 尺度通过天生规则界说了八个数据掩码:
- dark if (row + column) mod 2 == 0
- dark if (row) mod 2 == 0
- dark if (column) mod 3 == 0
- dark if (row + column) mod 3 == 0
- dark if ( floor(row / 2) + floor(column / 3) ) mod 2 == 0
- dark if ((row * column) mod 2) + ((row * column) mod 3) == 0
- dark if ( ((row * column) mod 2) + ((row * column) mod 3) ) mod 2 == 0
- dark if ( ((row + column) mod 2) + ((row * column) mod 3) ) mod 2 == 0
给定了规则我们很容易写出代码来天生这些掩码:
然则且慢,你看泛起在泛起了什么问题吗?
对,掩码的局限也覆盖了功能性区域,要是用这样的掩码的话,功能性标识也难以幸免。以是我们需要一个代表数据区域的“蒙版”来过滤掉功能性区域中的掩图案。这个“过滤”的历程可以通过矩阵间“与”运算来实现。
在 qrcode.py 最先添加矩阵间“与”运算函数和数据区域蒙版的填充:
填充出的数据区域蒙版效果如图
我们在界说掩码时和蒙版举行“与”运算,就可以获得局限准确的掩码了。继续添加掩码界说
效果如图
现在我们就可以安心地使用这些掩码啦!
在 qrcode.py 最先添加矩阵间异或函数
由于我们用 1 来示意白色,0 来示意玄色,以是异或和与的逻辑都是和正常逻辑相反的。
该实现 _mask 来给填了数据的 QR 码应用掩码了。可是纰谬啊,为什么要八个掩码啊?这是由于思量到数据的多样性,一种掩码难以达到预期的效果,以是 QR 尺度界说了八个掩码,要求在应用掩码时先划分应用所有的掩码发生八个效果,然后凭据责罚规则盘算出每个效果矩阵的责罚分,再选出责罚分最小,效果最好的掩码当做最终效果。这一历程发生的掩码 ID 也是花样信息的一部门,来告诉扫描软件应该用哪个掩码来还原数据。
QR 尺度把责罚分分成了四项,划分对应行/列中的延续色条、大面积的色块、行/列中类似定位标识的部门、整个矩阵中颜色的不平衡做出加权责罚。
(图片泉源:ISO/IEC 18004: Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
其中,N1=3,N2=3,N3=40,N4=10,i 是色条超出 5 的部门的长度。
在 _mask 之前添加 _penalty 的实现:
(插一句,我实现的这个 _penalty 还没有测试准确性。。)
(也许仔细看完了辣么一大段代码然后看到上一句的人会想来打我吧。。)
实现 _mask :
这里思量到 _mask 是由 _fillInfo 挪用,而填写花样信息需要选择的掩码的 ID,我们让 _mask 返回了效果矩阵和掩码 ID 组成的 tuple。
用我们之前的栗子测试一下掩码效果:
效果不错!
- 填充花样信息
只剩最后一步了!花样信息很简朴,由两位容错品级代码和三位 QR 掩码代码组成。
容错品级代码:
(图片泉源:ISO/IEC 18004: Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
QR 掩码代码:
固然花样信息也是要加容错码的。花样信息的容错算法接纳(15,5)。
编码
构建码字为
(c14, c13, ..., c8)
这样多项式为
c14+c13+...+c8
我们将它称为 CI。
然后就要找出 CR 知足 CR=CI (mod m1,3(x))=c7+c6+...+c0
这样就获得待发的码字 C(x) = CI+CR (mod m1,3(x)) = 0
例如,若是我们要对 (1,1,0,0,1,1,0) 举行编码
CI=x14+x13+x10+x9
然后用 m1,3(x) 除以(这里的除法是多项式除法)CI ,获得效果为 CR(x),在 Z2 域中,我们可以算出 CR 为
x3+1
这样,待发的码字为
(1,1,0,0,1,1,0, 0,0,0,0,1,0,0,1)
(Wikipedia: BCH 码,)
.......................................................
咳咳。。去看,都讲得很清晰嘛,很容易就看懂了对纰谬?(和善的微笑)
盘算得出十位 BCH 容错码接在花样信息之后,还要与掩码 101010000010010 举行异或,作用同 QR 掩码。
在 _fillInfo 之前添加 _fmtEncode 实现容错码盘算和应用掩码:
(Source: Wikiversity: )
有了编码好的花样信息,就可以把它凭据尺度填入矩阵了。
(图片泉源:ISO/IEC 18004: Information – Automatic identification and data capture techniques – QR Code barcode symbology specification)
其中 14 代表最高位(most significant bit),0 代表最低位(least significant bit)。
继续实现 _fillInfo:
至此 QR 码所有完成(撒花花 ︿( ̄︶ ̄)︿)。
- 接口
最后一步,为我们的 QR 码天生器提供挪用接口:
哒哒哒哒!完成!(完整版代码已上传 GitHub: )
别忘了我们最初的目的:hello world!来试验一下吧!
Hello world! (二维码自动识别)
能!扫!描!了!
满满的成就感有没有!!!
可是突然想到!!!
我只是想说一句 hello world 啊!!!!!
那何不多说几句啊!!
-
写在后面
破晓 2 点 14,终于完稿。我只有几点想说的
(END)
小鹿活码怎么注册_Hello World!_ 微信二维码
微信二维码登录原理
网页登陆是微信 4.2 以后版本提供的一种全新的登陆方式。用户只需要用手机扫一扫微信网页中的二维码,就能马上实现微信网页登陆。 这种登陆方式虽然炫酷,但是多少有些违背直觉: 网页端是怎么知道是哪个微信账号扫…
还没有人赞赏,快来当第一个赞赏的人吧!
- 2¥
- 5¥
- 10¥
- 20¥
- 50¥
声明:本文来自非凡建群宝投稿,不代表微信机器人立场,版权归原作者所有,欢迎分享本文,转载请保留出处!