【科普文】二維碼的[生成]和[掃碼]

做者:孫輝,美團金融前端團隊成員。15年畢業加入美團,相信技術,更相信技術只是大千世界裏知識的一種,我的博客: sunyuhui.comhtml

最近這段時間,團隊在作的業務主要和二維碼相關,在作的過程當中,發現不論是本身仍是團隊裏其餘同窗,都對二維碼自己瞭解甚少,所以本身調研了一番,在團隊內部作了一次分享,在這裏整理出來。前端

有意思的是以前在作業務時,QA跑過來問我一個問題:jquery

我兩次進入同一個頁面,發現圖片不同,是否是有問題啊?git

我當時很慶幸本身在作項目以前瞭解了一些二維碼相關的東西,因此我問他:github

你兩次掃碼的結果是同樣的嗎?shell

備註:本文涉及到的二維碼原理相對粗淺,只能當作二維碼的科普文,如有心對二維碼生成和掃碼原理有深刻研究,請出門左轉~canvas

二維碼的生成

二維碼的結構

爲了讓你們先直觀瞭解二維碼的結構,建議你們先去QR Code Generater,在左側的地址欄裏持續輸入不一樣的內容(隨便敲,使勁敲),在二維碼圖片的變動過程當中,仔細觀察圖片,看圖片的變化是否是有什麼規律。bash

這時候你內心應該大體有譜了,二維碼對你來講再也不只是混沌的黑白圖片,如今咱們來介紹下二維碼的結構微信



總體分爲功能區編碼區,功能區主要用於定位,編碼區則是真正存儲數據的。函數

有幾個地方須要注意:

  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. 二維碼的生成細節和原理
相關文章
相關標籤/搜索