QR 碼詳解(上)

關於二維碼,我查了下資料,如今基本都在用日本的 QR 碼,PDF417以及漢信碼平常基本看不到。緣由在於各方面來講,的確是 QR 碼最爲優秀。因此我準備寫一篇介紹 QR 碼的文章,若是是寫書,可能不方便寫得這麼詳盡,但若是是網上的文章,就能夠自由發揮了。寫完這篇文章,再抽取部份內容正規化,並整合其它內容造成書的第四章。爲方便將來上課講解方便,以及快速畫圖,我還作了一個《QR助手程序》,幫助繪製 QR 碼中的各部分圖形,最後演化成一個二維碼繪製程序。原本並未打算要本身寫二維碼繪製程序的,網上有不少現成的開發包。但一方面爲了讓本身更熟悉二維碼,另外一方面,用實現一個簡單的二維碼繪製程序讓學生參考,能夠有效下降學生的學習門檻。
 
QR 碼是日本發明的一種二維碼,也是目前應用最爲普遍的編碼。在中國,這種編碼幾乎無處不在,微信支付、支付寶支付、共享單車、各類廣告掃描關注等等。
 
1. QR 碼的特色
1. 存儲容量大
傳統的條形碼只能處理 20 位左右的信息,與此相比,QR 碼則可處理幾十倍上百倍的信息。另外,QR 碼還能夠支持全部類型的數據(如:數字、英文字母、日文字母、漢字、二進制、控制碼等)。一個 QR 碼最多可處理 7089 個數字的巨大信息量。

2. 佔用空間小
QR 碼使用縱向和橫向兩個方向處理數據,相同的信息量,QR 碼所佔空間更小。下圖分別是 GS1 編碼 `(02)66901234000049(17)050101(37)10(10)ABC`的 GS1-128 編碼和 QR 碼圖形。我先在屏幕上繪製圖形,而後使用掃碼槍掃描,接下來縮小圖形,直到掃碼槍認不出爲止。最後等比例放大,獲得下面繪製面積對比。

 
3. 糾錯能力強
QR 碼具有「糾錯功能」,即便部分編碼變髒或破損,也能夠恢復數據。數據恢復以碼字爲單位(是組成內部數據的單位,在QR碼的狀況下,每8比特表明1碼字),最多能夠糾錯約30%(根據變髒和破損程度的不一樣,也存在沒法恢復的狀況)。

4. 能夠從任意方向讀取
QR碼從360°任一方向都可快速讀取。QR碼中在 3 個定位圖案,能夠幫助QR碼不受背景樣式的影響,實現快速穩定的讀取。傳統激光掃碼槍在掃描條碼時,只能使用一個方向進行掃描,但若是使用的是 CCD 掃描槍,則能夠從任一方向掃描條碼。
 
2. QR 碼的結構
一個 QR 碼能夠分爲兩個部分:功能圖形和編碼區域。

功能圖形起到定位和校訂圖形的做用,數據區記錄了具體的數據信息、糾錯信息和版本信息。

2.1 QR 碼符號版本和規格
QR 碼符號共有 40 種規格,分別爲版本一、版本2……版本40。版本 1 的規格爲21模塊×21模塊,版本 2 的規格爲25模塊×25模塊,以此類推,每一版本符號比前一版本每邊增長4個模塊,直到版本40(規格爲177模塊×177模塊)。
 

由上圖可知,版本1圖形被劃分爲21×21個小方塊,模塊指的就是這些小方塊,是 QR 碼繪製的最小單元,在繪製 QR 碼時,將存在數據的模塊填充爲深色,最終組成 QR 碼圖形。下圖是版本40的模塊圖,由177×177個小方塊組成。


 2.2 尋像圖形
尋像圖形包括三個相同的位置探測圖形,分別位於二維碼左上角、右上角、左下角,每一個位置探測圖形由7×7個模塊組成以下圖所示:

 
符號中其餘地方遇到相似圖形的可能性極小,所以能夠在視場中迅速地識別可能的 QR 碼符號。識別組成尋像圖形的三個位置探測圖形,能夠明確地肯定視場中符號的位置和方向。下圖是版本1和版本6的尋像圖形,由圖可知,版本號越高,尋像圖形在整個圖案中所佔比例越小。


2.3 位置探測圖形分隔符
爲方便識別位置探測圖形,在每一個位置探測圖形和編碼區域之間有寬度爲 1 個模塊的分隔符,以下圖黃色區域所示。此區域應全爲空白,不能填入數據。


2.4 定位圖形
水平和垂直定位圖形分別爲一個模塊寬的一行和一列,由深色與淺色模塊交替組成,其開始和結尾都是深色模塊。水平和垂直定位圖形分別位於第6行和第6列(行、列由0開始計數),而且避開位置探測圖形。它們的做用是肯定符號的密度和版本,提供決定模塊座標的基準位置。下圖是繪製了定位圖形後的版本1和版本6圖案。


2.5 校訂圖形
校訂圖形做爲一個固定的參照圖形,在圖像有必定程度損壞的狀況下,譯碼軟件能夠經過它同步圖像模塊的座標映像。每一個校訂圖形由5×5模塊組成。以下圖所示:


校訂圖形的數量視符號和版本號而定,版本1沒有校訂圖形,版本2及以上均含有校訂圖形。校訂圖形的數量視 QR 碼的版本號而定。下表列出了前14個版本的數據,完整數據請查看國家標準 GB/T 18284-2000 中的附錄 E。



下面講講如何看懂中心模塊的行/列座標值。例如在版本 7 中,表中給出值 六、22 和 38。則校訂圖形的中心點位置行、列座標爲(6,22)(22,6)(22,22)(22.38)(38,22)(38,38)。因爲座標(6,6)(6,38)(38,6)座標位置被位置探測圖形佔據,所以,這些座標位置沒有放置校訂圖形。說白了就是將中心模塊的行/列座標值中的每一個值分別與本身及其餘值組成座標,而後刪除左上、右上、左下座標,即得出結果。

下圖是版本 1 及版本 7 的校訂圖形:


下圖是版本 15 及版本 40 的校訂圖形:


沒有固定公式計算中心模塊的行/列座標值,但觀察以上 4 張校訂圖形,能夠發現,QR 碼設計者在選擇座標值時,使得第一行和第一列校訂圖形正好融合進定位圖形,不會使定位圖形遭到破壞。

3. 數據編碼
各類用於圖像識別的功能圖形已經安放完畢,下一步就是對數據進行編碼了。標準 QR 碼可編碼數據類型有四種:數字、字母數字、8位字節和 Kanji,其中 Kanji 爲日文日文字符。咱們國家標準 GB/T 18284-2000 增長了 QR 碼的表示範圍。下表是 QR 碼可表示的數據類型及其相應的模式指示符。
 
模式 指示符    模式 指示符
ECI 0111   日文  1000 
數字 0001    中文 1101
字母數字 0010   FNC1 0101(第一位置)
8位字節 0100    FNC1 1001(第二位置)
表 1:模式指示符

ECI 是什麼東西,我很想搞懂,但很遺憾網上幾乎沒有資料,AIM ECI 規範的外文資料,需收費下載。沒辦法,等之後再說吧。如今只知道 AIM 是一家公司,ECI 是規範,有了這個規範,有了這個東西,可使用二維碼裝載各種不一樣的字符集,也可以使接收系統在數據被使用以前知道作哪些特定的擴展或解密處理。

FNC1 相信讀過前面寫的《條碼技術》這篇文章中的 GS1-128 條碼的都應當很熟悉,這類編碼是專爲 GS1 標準準備的。本文僅針對數字、字母數字、8 位字節以及 FNC1 模式進行講解,示例程序也只實現這四種編碼方式。

3.1 數字模式
數字模式只能對十進制數字 0~9 進行編碼,一般的密度爲 10 位表示 3 個字符。

3.1.1 將數字轉換爲位流
將要表示的數字從左邊開始每三位分爲一組,而後將每組數據轉換爲 10 位二進制(10 位二進制可表示的最大數字爲 1023)。若是最後一組數字只剩兩位,則使用 7 位二進制表示(7 位二進制可表示的最大數字爲 127)這兩個數字。若是最後一組數字只剩一位,則使用4位二進制表示最後一個數字(4 位二進制可表示的最大數字爲 15)。將二進制數據鏈接起來並在前面加上模式指示符和字符計數指示符。

**【例1】:** 數字`01234567`:
1. 分爲 3 位一組:012  345  67
2. 將每組轉換爲二進制:
    012 -> 0000001100
    345 -> 0101011001
     67 -> 1000011
3. 將二進制鏈接爲一個序列:0000001100 0101011001 1000011

3.1.2  將字符計數指示符轉換爲二進制
字符計數指示符表示裝載字符的個數,長度隨不一樣的 QR 碼版本以及模式而不一樣。表 2 列出了各版本及模式所對應的字符計數指示符的長度。
 
版本 數字模式 字母數字模式  8 位字節模式  中國漢字模式
1~9 10 9 8 8
10~26 12 11 16 10
27~40  14 13 16 12
表 2:字符計數指示符的位數

數據的數字位數爲 8,查上表數字模式列,若是使用版本 1 來表示,則位數爲 10。最終:
8 -> 0000001000

#### 加入模式指示符及字符計數指示符
查表 1 ,數字模式的指示符爲 0001。以【模式指示符 + 字符計數指示符 + 數字位流】的方式鏈接數據最終位流爲:

0001 0000001000 0000001100 0101011001 1000011

接下來再作一個例子加深理解:

**【例2】:** 數字`0123456789012345`:
1. 分爲 3 位一組:012  345  678  901  234  5
2. 將每組轉換爲二進制:
    012 -> 0000001100
    345 -> 0101011001
    678 -> 1010100110
    901 -> 1110000101
    234 -> 0011101010
      5 -> 0101
3. 將二進制鏈接爲一個序列:
    0000001100 0101011001 1010100110 1110000101 0011101010 0101

4. 數字位數爲 16,使用版本 1 表示,位數爲 10。最終:
16 -> 0000010000

5. 加上數字模式的指示符 0001 最終位流爲:
    0001 0000010000 0000001100 0101011001 1010100110 1110000101 0011101010 0101

3.2 字母數字模式
字母數字模式對 45 個字符的字符集進行編碼,即:10 個數字 0~9,26 個大寫字母 A~Z,以及 9 個符號 SP、$、%、*、+、-、.、/。一般狀況下,兩個輸入字符用 11 位表示。下表是 45 個字符及其編碼:
字符   字符   字符   字符   字符
0 0   9 9   I 18   R 27   SP 36
1 1   A 10   J 19   S 28   $ 37
2 2   B 11   K 20   T 29   % 38
3 3   C 12   L 21   U 30   * 39
4 4   D 13   M 22   V 31   + 40
5 5   E 14   N 23   W 32   - 41
6 6   F 15   O 24   X 33   . 42
7 7   G 16   P 25   Y 34   / 43
8 8   H 17   Q 26   Z 35   : 44

要完整表示 45 個字符中的一個,須要至 6 個位的二進制數字($2^6=64$),那麼每兩個字符須要佔用 12 個位的空間。QR 碼使用了另外一種編碼方法,將表示兩個字符壓縮爲使用 11 個位的空間。

將輸入的數字分爲兩個字符一組,將左邊的字符的值乘以 45 與第二個字符的值相加,將所得的結果轉換爲 11 位二進制數。最大字符組爲"::"(44×45+44=2024,而2 11=2048)。若是輸入的數據的字符不是 2 的倍數,將最後一個字符編碼爲 6 位二進制數。將所得的二進制數鏈接起來並在前面加上模式指示符和字符計數指示符,獲得最終編碼。

**【例 3】:** 數據`AC-42`,QR 碼版本號 1:
1. 根據表 5 查出字符的值:AC-42 -> (10,12,41,4,2)
2. 將結果分爲 2 個一組:(10,12)(41,4)(2)
3. 將每組數據轉換爲 11 位二進制數:
    (10,12) -> 10×45+12=462 -> 00111001110
    (41,4) -> 41×45+4=1849 -> 11100111001
    (2) -> 2 -> 000010
4. 二進制數據順次鏈接獲得數據位流: 00111001110 11100111001 000010
5. 字符數爲 5,查表2,使用 9 位二進制數表示。將字符計數指示符轉換爲二進制,
    5 -> 000000101
6. 查表 1,模式指示符爲 0010。以【模式指示符 + 字符計數指示符 + 數字位流】的方式鏈接數據最終位流爲:
    0010 000000101 00111001110 11100111001 000010

3.3  8 位字節模式
在 8 位字節模式中,一個 8 位碼字直接表示一個輸入數據字符的 ASCII 字符值(ASCII 譯碼錶請查[這裏](http://iotxfd.cn/demo/ascii.html))。即密度爲每一個字符 8 位。將二進制數據鏈接起來並在前面加上模式指示符和字符計數指示符,獲得最終編碼。

**【例 4】:** 數據`Ab>Cd`,QR 碼版本號 1:
1. 在 ASCII表中查出各字符的值,並轉換爲 8 位二進制:
    A -> 65 -> 01000001
    b -> 98 -> 01100010
    `>` -> 62 -> 00111110
    C -> 67 -> 01000011
    d -> 100 -> 01100100
2.  二進制數據順次鏈接獲得數據位流:01000001 01100010 00111110 01000011 01100100
3. 字符數爲 5,查表2,使用 8 位二進制數表示。將字符計數指示符轉換爲二進制,
    5 -> 00000101
4. 查表 1,模式指示符爲 0100。以【模式指示符 + 字符計數指示符 + 數字位流】的方式鏈接數據最終位流爲:
    0100 00000101 01000001 01100010 00111110 01000011 01100100

3.4 混合模式
以前在學習 Code 128 編碼時你們應該還記得,爲了達到符號長度最小的目的,Code 128 條碼支持混合編碼的方式。QR 碼也支持以混合方式進行編碼。其基本結構爲【模式指示符 + 字符計數指示符 + 數據】,其後緊跟下一段的指示符開始另外一段。下圖爲有 n 段數據的結構。


因爲 GS1 標準僅支持 ASCII 碼,這裏只針對數字模式、字母數字模式、8 位字節模式的混合編碼進行討論。如下是針對上述模式的編碼規則,完整編碼規則請參考 GB/T 18284-2000 的附錄 H。

3.4.1 位流長度最優化的編碼規則
下列是造成最短位流的算法的基礎。在方括號中的字符數如[5,7,9]分別用於版本 1~9,10~26 和版本 27~40。

1. 選擇初始模式
    * 若是初始輸入數據是在 8 位字節的二進制字符的專有子集中,選擇 8 位字節模式;
    * 若是初始輸入數據是在字母數字字符集的專有子集中,而且若是字符個數少於[6,7,8],其後緊跟 8 位字節專有子集中的數據,那麼選擇 8 位字節模式,不然選擇字母數據模式;
    * 若是初始數據是數字,而且若是數字個數少於[4,4,5],其後緊跟 8 位字節字符集專有子集中的數據,那麼選擇 8 位字節模式,不然若是少於[6,7,8]後隨字母數字字符集的專有子集中的數據,那麼選擇字母數字模式,不然選擇數字模式。
2. 在 8 位字節模式中
    * 若是有很多於[6,8,9]的數字字符序列出如今來自 8 位字節二進制字符集的專有子集的多個數據前,那麼轉至數字模式;
    * 若是有字母數字字符集的專有子集的很多於[11,15,16]的字符序列出如今來自 8 位字節二進制字符集的專有子集的數據前,那麼轉至字母數字模式。
3. 在字母數字模式中
    * 若是有 8 位字節字符集的專有子集的一個或多個字符出現,轉至 8 位字節模式;
    * 若是有很多於[13,15,17]的數字字符數據序列在來自字母數字字符集的專有子集的數據前出現,轉至數字模式。
4. 在數字模式中
    * 若是有一個或多個來自 8 位字節的專有子集中的字符出現,轉至 8 位字節模式;
    * 若是有一個或多個字母數字的專有子集中的字符出現,轉至字母數字模式。

> 編者注:上述規則摘抄至 GB/T 18284-2000,最後一句是有問題或者不完善的。若是在數字模式中出現字符`Aabcd`,由於`A`屬於字母數字字符集,而`abcd`只屬於 8 位字節字符集。此時按最後一句話,需先轉換爲字母數字模式,加入字符`A`,而後立刻又轉換爲 8 位字節模式。很顯然,這樣作浪費了空間。因爲字母數字字符集是 8 位字節字符集的子集,正確的作法應當是轉換爲 8 位字節模式,而後加入字符`Aabcd`。

**【例 5】:** 數據`123456ABC123`,QR 碼版本號 1:
1. 根據編碼規則,首先應選擇數字模式做爲初始模式:0001
2. 加入字符計數指示符:6 -> 0000000110
3. 加入 123 編碼:123 -> 0001111011
4. 加入 456 編碼:456 -> 0111001000
5. 根據編碼規則,轉換爲字母數字模式:0010
6. 加入字符計數指示符:6 -> 000000110
7. 加入 AB 編碼:(10,11) -> 10×45+11=461 -> 00111001101
8. 加入 C1 編碼:(12,1) -> 12×45+1=541 -> 01000011101
9. 加入 23 編碼:(2,3) -> 2×45+3=93 -> 00001011101

將以上生成的二進制數據從上至下鏈接,生成最終位流。

3.5 FNC1 模式
FNC1 模式有兩種模式指示符,用於標識按特定的行業或應用格式化信息的符號。FNC1 在第一位置時支持 GS1 標準,FNC1 在第二位置時支持按 AIM 承認的特定行業或者特定應用規範格式化信息。因爲 AIM 查不到資料,這裏只介紹 FNC1 第一位置模式,即模式指示符爲:0101。

在 GS1-128 中,FNC1 用於數據段分隔,而 QR 碼中沒有專用的 FNC1 字符,在字母數字模式中用 % 字符代替,若是在數據中也有 % 符號出現,則 應按 %% 進行編碼。在 8 位字節模式中用字符 GS(ASCII 值 29)代替。

> 編者注:我的感受,這個設計方式相比 GS1-128 來講,並不太合理。即便數據只是純數字,但只要在其中須要分段,安置 FNC1 ,就必須轉爲字母數字模式,若是後面還有足夠多的數字,還得再次轉回來。這樣作的成本過高了。數字模式,還有部分未使用的編碼,應當有自已的 FNC1,即便這個編碼佔據 10 個位,仍是合算的。

**【例 6】:** 數據`(02)66901234000049(17)050101(37)10(10)ABC`,QR 碼版本號 1:
首先分析數據中的 AI:(02)表示物流單元內貿易項目,長度固定;(17)表示有效期,長度固定;(37)表示物流單元內貿易項目數量,長度不固定,需在此 AI 最後加入 FNC1;(10)表示批號,長度不固定,它爲最後一個 AI,無需加入 FNC1 標誌。最終編碼變爲:

`(02)66901234000049(17)050101(37)10<FNC1>(10)ABC`

編碼過程:

1. 將 FNC1 第一位置做爲初始模式:0101
2. 根據位流長度最優化的編碼規則,加入數字模式指示符:0001
3. 加入字符計數指示符:28 -> 0000011100
4. 加入 026 編碼:026 -> 0000011010
5. 加入 690 編碼:690 -> 1010110010
6. 加入 123 編碼:123 -> 0001111011
7. 加入 400 編碼:400 -> 0110010000
8. 加入 004 編碼:004 -> 0000000100
9. 加入 917 編碼:917 -> 1110010101
10. 加入 050 編碼:050 -> 0000110010
11. 加入 101 編碼:101 -> 0001100101
12. 加入 371 編碼:371 -> 0101110011
13. 加入 0 編碼:0 -> 0000
14. 根據編碼規則,轉換爲字母數字模式:0010
15. 加入字符計數指示符:6 -> 000000110
16. 加入 %1 編碼:(38,1) -> 38×45+1=1711 -> 11010101111
17. 加入 0A 編碼:(0,10) -> 0×45+10=10 -> 00000001010
18. 加入 BC 編碼:(11,12) -> 11×45+12=507 -> 00111111011

將以上生成的二進制數據從上至下鏈接,生成最終位流。

3.6  終止符
符號的數據結尾由緊跟在最後一個模式段後面的終止符序列 0000 表示,當數據位流數量正好填滿符號容量時,它能夠省略,或者當符號所餘的容量不足 4 位時它能夠截短。

3.7  位流到碼字的轉換
每一個模式段的位流須要按順序鏈接在一塊兒,最後添加終止符,除非數據位流正好填滿符號容量。所得的數據位流將被分爲一個個碼字;全部碼字長度都是 8 位,若是位流長度最後一個碼字不足 8 位,則用二進制值爲 0 的填充位填充至 8 位,填充位應加在數據位流最後 1 位(最低位)的後面。說白了就是將位流進行 8 位對齊。

咱們以【例 1】最終生成的數據位流爲例說明上述過程。

1. 【例 1】最終生成的數據位流:000000110001010110011000011
2. 加入終止符 0000,(如今符號容量足夠,不用考慮容量不足的狀況):
    0000001100010101100110000110000
3. 將數據位流劃分爲碼字,這裏在每 8 個位後加一個逗號表示:
    00000011,00010101,10011000,0110000
4. 咱們發現最後一個碼字只有 7 位數字,不足 8 位,補 1 個零,最終數據變爲:
    00000011,00010101,10011000,01100000

最終【例 1】生成的數據使用了 4 個碼字。

接下來就要查表了,下表列出了各個版本 QR 碼的碼字容量,這裏只列出一小部分,完整表格請參考 GB/T 18284-2000。


注意表格中的紅框部分,因爲只使用了 4 個碼字,咱們徹底能夠選擇最高糾錯等級 H。因此最終選擇爲:版本 1 的 H 糾錯等級 QR 碼。在此等級中可放置 9 個碼字,還剩餘 5 個碼字是不能放空的,須要交替填充碼字 11101100 和 00010001,直至填滿整個 9 個碼字。

5. 將空位填滿至 9 個碼字,最終數據變爲:
    00000011,00010101,10011000,01100000,11101100,00010001,11101100,00010001,11101100

好!上半場結束,圖多,仍是分兩篇寫吧。下半場內容就比較抽象了。
相關文章
相關標籤/搜索