QrCode二維碼的實現原理


TOC

前言

得益於微信的推廣,QR二維碼可以說已經融入了生活的方方面面,通過二維碼極大的縮短了業務流程路徑,目前日常最常用的場景莫過於支付、登錄認證、信息識別等。希望通過對二維碼的學習,了解其背后的原理,在以后的工作中能加以運用。

什么是二維碼

二維碼也稱為二維條碼,是指在一維條碼的基礎上擴展出另一維具有可讀性的條碼,使用黑白矩形圖案表示二進制數據,被設備掃描后可獲取其中所包含的信息。一維條碼的寬度記載着數據,而其長度沒有記載數據。二維碼的長度、寬度均記載着數據。二維碼有一維條碼沒有的“定位點”和“容錯機制”。容錯機制在即使沒有識別到全部的條碼、或是說條碼有污損時,也可以正確地還原條碼上的信息。
二維碼的種類很多,不同的機構開發出的二維碼具有不同的結構以及編寫、讀取方法。常見的二維碼有:
PDF417碼、QR碼、漢信碼、顏色條碼、EZ碼、Aztec碼、QuickMark、Data Matrix。
注意:由於QR碼目前普及度最高,所以一般人們所說的二維碼=QR碼。

什么是QR碼

QR碼(全稱為快速響應矩陣圖碼;英語:Quick Response Code)是二維碼的一種,於1994年由日本DENSO WAVE公司(豐田的子公司,生產汽車零部件)發明,該標准在ISO/IEC 18004:2015中定義,是免費使用的。QR來自英文Quick Response的縮寫,即快速反應,因為發明者希望QR碼可以快速解碼其內容。QR碼使用四種標准化編碼模式(數字、字母數字、字節(二進制)和日文(Shift_JIS))來存儲數據。QR碼常見於日本,為目前日本最通用的二維空間條碼,在世界各國廣泛運用於手機讀碼操作。QR碼比普通一維條碼具有快速讀取和更大的存儲數據容量,也無需要像一維條碼般在掃描時需要直線對准掃描儀。

特點:
1.存儲大容量信息
2.在小空間內打印
3.有效表現各種字母
4.對變臟和破損的適應能力強
5.可以從任意方向讀取
6.支持數據合並功能

創建QR碼的步驟

數據分析

QR標准具有四種用於編碼文本的模式:數字,字母數字,字節和漢字。每種模式都將文本編碼為一位(1或0),但是每種模式都使用不同的方法將文本轉換為位,並且每種編碼方法都經過了優化,可以使用盡可能短的位串對數據進行編碼。因此,第一步應該是執行數據分析,以確定文本是以數字,字母數字,字節還是漢字模式進行編碼,選擇最佳編碼模式。
(1)如果輸入字符串僅包含十進制數字(0到9),用數字模式。
(2)如果數字模式不適用,並且可以在字母數字表的左列中找到輸入字符串中的所有字符,用字母數字模式。注:小寫字母不能以字母數字模式編碼;僅大寫。
(3)如果某個字符不在字母數字表的左列中,但可以在ISO 8859-1中進行編碼,用字節模式。
(4)QR碼閱讀器可能能夠以字節模式識別UTF-8。 如果所有字符都在Shift JIS字符集中,用漢字模式。 Shift JIS字符可以改用UTF-8編碼,因此可以將字節模式用於漢字,但通常更有效的方式是使用Shift JIS並將漢字模式用於漢字字符(省空間)。

編碼

不同的編碼模式是為了使得我們轉碼的比特串長度最短。

(1)選擇糾錯碼級別

在編碼之前,需要先選擇糾錯碼級別

錯誤修正容量
L等級 7%的字碼可被修正
M等級 15%的字碼可被修正
Q等級 25%的字碼可被修正
H等級 30%的字碼可被修正

(2)確定數據的最小版本

不同版本的QR碼尺寸不同,目前有40個版本,從1到40,每個版本比之前的大4像素。由於糾錯碼也占用空間,所以不同版本不同糾錯級別的容量也不一樣,具體可以參考這里

(3)添加模式標識

每個編碼模式都有一個標識它的四位模式標識。編碼的數據必須以適當的模式標識開頭,下表列出了每種模式的模式標識。

模式名稱 標識
Numeric Mode 0001
Alphanumeric Mode 0010
Byte Mode 0100
Kanji Mode 1000
ECI Mode 0111

(4)添加字符數標識

字符計數指示器是一串字符串,代表要編碼的字符數。需要注意的是,字符數標識基於不同的QR版本有不同的固定長度,如果實際字符長度不滿,則需要在左側補0。

  • 版本1 到 9
    Numeric mode: 10 bits
    Alphanumeric mode: 9 bits
    Byte mode: 8 bits
    Japanese mode: 8 bits
  • 版本10到 26
    Numeric mode: 12 bits
    Alphanumeric mode: 11 bits
    Byte mode: 16
    Japanese mode: 10 bits
  • 版本27到 40
    Numeric mode: 14 bits
    Alphanumeric mode: 13 bits
    Byte mode: 16 bits
    Japanese mode: 12 bits

例如,我們選擇Alphanumeric模式和version1來編碼HELLO WORLD,那么查表可以知道,Alphanumeric模式的字符數標識固定長度為9bits,HELLO WORLD的長度為11,轉換成二進制為1011,不足9位左側補0,即000001011,然后再把第三步中的模式標識放在前面。
最終:0010 000001011

(5)進行編碼

不同的編碼模式,有不同的算法,具體可以參考下面幾個頁面。

以上述的HELLO WORLD為例,采用Alphanumeric Mode Encoding
需要注意的是:alphanumeric模式只能編碼大寫字母
1、拆成字符對:HE, LL, O (空格), WO, RL, D
2、參考字母數字表,轉換成對應的數字,然后用第一個字符數字*45+第二個字符數字,再轉換成二進制,一個字符補滿6位,兩個字符補滿11位。例如:HE=(45*17)+14=779,再轉換成二進制
779 → 01100001011
那么最終我們得到的編碼數據為

Mode Indicator Character Count Indicator Encoded Data
0010 000001011 01100001011 01111000110 10001011100 10110111000 10011010100 001101

(6)拆分比特串成8位一組,不足補0;

1、首先要確定當前QR碼所需長度,不同的糾錯碼長度不一致,可以查詢參考此表,可以查出所需塊組數,然后記得要乘以8。
例如1-Q的碼,查表可知需要13組,那么最終的QR碼長度為13*8=104bits。
2、添加終止標識
如果位字符串短於所需位的總數,則必須在字符串的右側添加最多四個0的終止標識,如果位串短於少於四位,則僅添加達到所需位數所需的0。
從上面可知HELLO WORLD的編碼長度為74位,不滿104,終止標識必須補4位。

Mode Indicator Character Count Indicator Encoded Data Terminator
0010 000001011 01100001011 01111000110 10001011100 10110111000 10011010100 001101 0000

3、末尾補0,確保每組長度為8位。
在添加終止標示符之后,總長度變為78位,不能被8整除,還需要補2位。
即00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 01000000
4、如果長度不夠,繼續補位
經過上面步驟之后,長度目前變成了80位,還差104-80=24位,那么我們需要重復添加11101100 00010001直到字符串達到最大長度為止,這兩個字節轉換成數字即236和17,至於為什么是這兩個數,協議規定的,添加就對了(也許有彩蛋?)。
那么最終編碼結果數據碼為:
00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 01000000 11101100 00010001 11101100

生成糾錯編碼

QR碼具有糾錯能力,當完成編碼之后,會用這些數據通過一種叫做Reed-Solomon算法糾錯的過程生成糾錯碼。
QR掃描時同時讀取數據代碼字和糾錯代碼字。通過比較兩者,掃描儀可以確定它是否正確讀取了數據,如果沒有正確讀取數據,則可以糾正錯誤。
相對而言,容錯率愈高,QR碼圖形面積愈大。所以一般折衷使用15%容錯能力。

錯誤修正容量
L等級 7%的字碼可被修正
M等級 15%的字碼可被修正
Q等級 25%的字碼可被修正
H等級 30%的字碼可被修正

(1)將數據碼按順序分組分塊
生產糾錯碼之前,我們需要查表將數據碼(1字節=8位)分組,不同組里可能還存在不同的塊,例如5-Q的QR碼,查表可知,分為兩組,每組包含2個塊,組1的塊大小為15字節,組2塊大小為16字節,那么15+15+16+16 = 62字節,又可知每組塊所需糾錯碼大小為18,那么糾錯碼總大小為4*18=72字節。
具體算法過程見這里,不詳細說明

生成最終的數據結構

在數據和糾錯碼都生成好了之后,需要將他們以正確的順序排列。對於小型QR碼,將糾錯碼添加到數據碼后面即可。
對於大型QR碼,數據和糾錯碼字是在塊中生成的,並且必須根據QR碼規范對這些塊進行交織。
例如對於5-Q版本2組4塊16個字節的數據碼:

. Col 1 Col 2 Col 3 Col 4 Col 5 Col 6 Col 7 Col 8 Col 9 Col 10 Col 11 Col 12 Col 13 Col 14 Col 15 Col 16
Block 1 67 85 70 134 87 38 85 194 119 50 6 18 6 103 38
Block 2 246 246 66 7 118 134 242 7 38 86 22 198 199 146 6
Block 3 182 230 247 119 50 7 118 134 87 38 82 6 134 151 50 7
Block 4 70 247 118 86 194 6 151 50 16 236 17 236 17 236 17 236

那么把每一列數據拼接即可:
(67,246,182,70),(85,246,230,247)……以此類推。
糾錯碼同理。
最終將交織的糾錯碼添加到交織的數據碼后面,如:
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
然后轉換成二進制
0100001111110110101101100100011001010101111101101110011011110111010001100100001011110111011101101000011000000111011101110101011001010111011101100011001011000010001001101000011000000111000001100101010111110010011101101001011111000010000001111000011000110010011101110010011001010111000100000011001001010110001001101110110000000110000101100101001000010001000100101100011000000110111011000000011011000111100001100001000101100111100100101001011111101100001001100000011000110010000100010000011111101100110101010101011110010100111010111100011111001100011101001001111100001011011000001011000100000101001011010011110011010100101011010111001111001010010011000001100011110111101101101000010110010011111100010111110001001011001110111101111110011101111100100010000111100101110010001110111001101010111110001000011001001100001010001001101000011011110000111111111101110101100000011110011010101100100110101101000110111101010100100110111100010001000010100000001001010110101000110110110010000011101000011010001111110000001000000110111101111000110000001011001000100111100001011000110111101100
不同版本需要補零,可查表
所以對於最后的11101100,我們需要補7個0,既111011000000000

將數據塊放置二維碼矩陣中

(1)放置固定圖案

定位圖案(finder patterns):位於圖案左上、左下、右上的黑塊,用於定位二維碼
分隔符(separators):位於定位器周圍的白邊
校准圖案(alignment patterns):和定位圖案類似,可能會貫穿於於整個二維碼,通常存在於版本2以上的二維碼,具體位置取決於二維碼版本。
時序圖案(timing patterns) :類似虛線,用於連接定位圖案。
黑塊(dark module):獨立的黑塊,始終放在左下的定位圖案旁,用於保留格式、版本信息。
具體如何放置見這里

(2)放置數據位


白色表示0,黑色表示1,順序如圖所示,一次占兩列
向上


向下


當遇到固定圖案時,跳過,直到遇到未使用的二維碼塊。

添加掩碼

QR碼中的某些模式可能會使QR碼掃描器難以正確讀取代碼。為了解決這個問題,QR碼規范定義了八個掩碼圖案,每個掩碼圖案都會根據特定圖案更改QR碼。我們可以通過基於四個懲罰規則的得分來確定這些掩碼圖案中的哪一個會導致QR碼具有最少的不良特征,最終的QR碼必須使用最低分的掩碼圖案。
掩碼有八種款式如下圖,可以使掩碼的黑色的區域反轉:

評價標准如下:

  1. 行(列)中有連續 a 個模塊(a>5)同色,每處計 3+(a-5)=a-2 分;
  2. 模塊同色構成的 m 行 n 列矩形,每處計 3(m-1)(n-1) 分;
  3. 行(列)中出現 1:1:3:1:1(黑白黑白黑)的圖形(上圖所謂的后者因素),每處計 40 分;
  4. 黑色模塊比率為 x%,則計 分。

添加格式和版本信息

最后一步是通過在代碼的特定區域添加在先前步驟中留為空白的像素,向QR碼添加格式和版本信息(如果有必要)。格式像素標識此QR碼中使用的糾錯級別和掩碼模式。版本像素對QR矩陣的大小進行編碼,並且僅在較大的QR碼中使用。
QR碼一共提供40種不同版本存儲密度的結構,對應指示圖的“版本信息”,版本1為21×21模塊(模塊為QR碼中的最小單元),每增加一個版本,長寬各增加4個模塊,最大的版本40為177×177模塊。

QR碼最大數據容量 (對於版本40)
數字 最多7,089字符
字母 最多4,296字符
二進制數(8 bit) 最多2,953 字節
日文漢字/片假名 最多1,817字符(采用Shift JIS)
中文漢字 最多984字符(采用UTF-8)
中文漢字 最多1,800字符(采用BIG5/GB2312)

(1)格式信息

Error Correction Level Bits Integer Equivalent
L 01 1
M 00 0
Q 11 3
H 10 2

例如糾錯級別L,掩碼模式4的二維碼,格式信息二進制為01100
其中100=2^2=4
通過算法再生成糾錯碼,最終為110011000101111
為了減少計算,可以直接查表
最后,將二進制位橫豎按標識貼到如圖所示的位置。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 1 0 0 1 1 0 0 0 1 0 1 1 1 1

無論二維碼版本大小,都可以進行標識。

(2)版本信息

如果是大於版本7的二維碼,必須添加18位的版本信息到如圖所示的位置:

算法同上,查表即可。
例如版本7,000111110010010100
17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 1 1 1 1 1 0 0 1 0 0 1 0 1 0 0
左下角的填充順序:
00 03 06 09 12 15
01 04 07 10 13 16
02 05 08 11 14 17
右上角的填充順序:
00 01 02
03 04 05
06 07 08
09 10 11
12 13 14
15 16 17

輸出最終的二維碼

需要注意,為了提高識別率,一般會加上4個圖塊寬的空白區域
下圖是通過alphanumeric mode編碼、1-Q版本的“HELLO WORLD”

參考

https://www.thonky.com/qr-code-tutorial/introduction


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM