【科普文】二维码的[生成]和[扫码]

·  阅读 8861

作者:孙辉,美团金融前端团队成员。15年毕业加入美团,相信技术,更相信技术只是大千世界里知识的一种,个人博客: sunyuhui.com

最近这段时间,团队在做的业务主要和二维码相关,在做的过程中,发现不管是自己还是团队里其他同学,都对二维码本身了解甚少,因此自己调研了一番,在团队内部做了一次分享,在这里整理出来。

有意思的是之前在做业务时,QA跑过来问我一个问题:

我两次进入同一个页面,发现图片不一样,是不是有问题啊?

我当时很庆幸自己在做项目之前了解了一些二维码相关的东西,所以我问他:

你两次扫码的结果是一样的吗?

备注:本文涉及到的二维码原理相对粗浅,只能当做二维码的科普文,若有心对二维码生成和扫码原理有深入研究,请出门左转~

二维码的生成

二维码的结构

为了让大家先直观了解二维码的结构,建议大家先去QR Code Generater,在左侧的地址栏里持续输入不同的内容(随便敲,使劲敲),在二维码图片的变更过程中,仔细观察图片,看图片的变化是不是有什么规律。

这时候你心里应该大致有谱了,二维码对你来说不再只是混沌的黑白图片,现在我们来介绍下二维码的结构



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

有几个地方需要注意:

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

二维码是如何生成的?

那上面的二维码到底是怎么一步步生成的呢?



上面的图中,详细标注出了二维码的各个结构生成的顺序。左边的流程图是绘制的顺序,右边的图表示绘制到这个流程时已经绘制出来的图形。比如,绘制到【定位图形】这一步时,整个二维码就已经有了左上角、右上角、左小角、连接这三者的横竖两条定位标志以及右下方的校正标志

添加【掩码图案】这个阶段时,整个二维码其实已经绘制完成了,但是如果只是按照实际的信息来绘制,可能会导致页面上有一大片黑色或者一大片白色,而不是我们现在看到的黑白交叉的图形,这样会导致扫码时识别困难。所以在这一步会再做一步操作:从已有的模板中(模板的黑白是交叉的)选一个,来和生成的二维码图形做异或操作,其中异或操作就是JavaScript中的^运算符

其实在整个生成过程中,我最好奇的是这些黑白色是怎么生成的(恩,我相信你也是这样的 ^-^ )。

现在我们以 jquery-qrcode 为例,看下源码

options    = $.extend( {}, {
    render                : "canvas",
    width                : 256,
    height                : 256,
    typeNumber        : -1,
    correctLevel        : QRErrorCorrectLevel.H,
    background      : "#ffffff",
    foreground      : "#000000"
}, options);复制代码

这里是生成二维码时的一些参数,可以看到参数里有个background属性和foreground属性,分别为白色黑色,咦?这么巧?

继续看

// draw in the canvas
for( var row = 0; row < qrcode.getModuleCount(); row++ ){
    for( var col = 0; col < qrcode.getModuleCount(); col++ ){
        ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;
        var w = (Math.ceil((col+1)*tileW) - Math.floor(col*tileW));
        var h = (Math.ceil((row+1)*tileW) - Math.floor(row*tileW));
        ctx.fillRect(Math.round(col*tileW),Math.round(row*tileH), w, h);  
    }    
}复制代码

这里就是二层循环,用来绘制二维码的内容(二维码是矩形,所以两层循环),其中有行代码鹤立鸡群,立马引起了我的注意:

ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;

isDark函数是干啥的?我们去 源码 瞅瞅,然后就能发现,这个函数其实返回的就是二维码里这个位置上的二进制数据,从 这篇文章 里我们知道二维码生成过程中,会把所有信息都转换成二进制,所以二维码内容上的数据不是0就是1,那么在isDark函数里,我们发现,如果位置上的数据是1,就使用白色,如果数据是0,就使用黑色

恩, 这时候就知道为啥二维码是黑白的了吧。

生成二维码时的几个问题

1. 二维码只能是黑白的吗?

源码在手,天下我有

所以让我们来尝试着生成彩色的二维码吧!

我们把生成二维码的foreground参数和background参数修改一下,

options = $.extend( {}, {
render : "canvas",
width : 256,
height : 256,
typeNumber : -1,
correctLevel : QRErrorCorrectLevel.H,
background : "#f00", //改成红色
foreground : "#0f0" //改成绿色
}, options);

恩,是的,我们生成了一个大红大绿的二维码。。。。。绿色对应原来的白色,红色对应原来的黑色。(我打赌,你之前肯定没有见过这么艳的二维码 ~



2. 同样的内容生成的二维码是不同的吗?

不是相同的,就如同我们开篇QA提到的那样,不过扫码后得到的结果是一样的。不同的原因是由于在具体生成黑白块时,是按照一定规律随机放置在图片中的。

3. 既然可以生成彩色的,为啥我们平常见到的二维码都是黑白的?

嗯,好问题,这个问题我们稍后解答~

二维码的[扫码]

大家平常在用各种APP扫码的时候,主要是付款、取(电影)票、添加微信好友等一些场景

我们能明显感受到的只是那的一声,那么在扫码的时候究竟发生了什么呢?我最近在做的业务中就有一环是【扫码】,所以我研究了一下。整体流程图是这样的



总的来说,扫码的流程就是两步:

  1. 获取二维码图片信息
  2. 对图片信息做相应处理

这时候你再回想下自己在微信、美团、点评等APP里使用扫码功能时出现的不同情况,恩,你应该明白了。。

也许你已经习惯了每次扫码都会跳转到一个新页面,又或者你平常根本没注意这种事,但并不总是 扫码后跳转到一个链接 这么简单,而是对扫码返回的信息做不同处理。跳转到一个链接 只是其中一种方式。

在生成二维码时,我们提过到,二维码的生成过程,就是一个对信息加密的过程,那么【扫码】这个过程呢?其实就是一个解密的过程。具体怎么去解密的,可以去读一下Zxing的源码

扫码时的几个问题

拍照用的摄像头和扫码用的摄像头有什么区别?

其实都是调用的手机的摄像头,但是扫码的摄像头由APP控制,具备解析二维码内容的能力。

为啥大家见到的二维码都是黑白的?

即便是从颜值上考虑,彩色的也会更好看,在如今颜值即正义的时代里,不可能有人想不到用彩色的二维码来代替黑白的。

原因是由于:黑白二维码扫码速度更快,对于手机摄像头来说,要读取信息,就要获取图片中的两种二进制信息(1和0),在前文已经说过,1代表白色,0代表黑色,黑色的色值是#000000,白色的色值是#ffffff,在所有颜色中,只有黑色和白色的色值差是最大的,对手机来说,也就更容易区分了,但是如果我们用其他的两种颜色来代替黑色和白色呢?其实我已经在前文里把彩色二维码给大家展现了,大家可以分别扫一下彩色的二维码和黑白的二维码,应该能明显感觉到黑白的更快。

扫码时的速度取决于什么?

这个问题可能是很多做二维码相关业务的人关注的事情了,因素也有多方面的。

从二维码的角度:

  1. 二维码的平整度(二维码都放在一个壳子里)
  2. 二维码内容的辨识度(能看到的基本都是黑白的)
  3. 存续的信息量大小(以现在手机的处理能力,这个因素影响很小)

从手机的角度

  1. 不同的APP针对扫码做的优化措施不一样,比如微信就做了很多优化措施。
  2. 摄像头硬件配置

其中二维码的平整度(二维码都放在一个壳子里)这个因素,大家平常在外面吃东西扫二维码付款时,应该都可以看到二维码是放在一个白色的壳子里,我不知道这是不是各大公司有意识的做这件事,也许他们只是想延长二维码的使用寿命,但这个措施确实做的非常好。

ok,到这里就差不多了,希望看完这篇文章之后,大家对二维码应该有了一些了解,不会像以前一样,二维码对大家来说只是一张黑白图片。

Done.

最后,团队为了招聘方便,整了个公众号,主要是一些招聘信息,团队信息,所有的技术文章在公众号里也可以看到,对了,如果你想去美团其他团队,我们也可以帮你内推哦 ~

二维码
二维码

参考:

  1. 二维码的生成细节和原理
分类:
前端
标签:
分类:
前端
标签: