二维码的生成细节和原理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
二維碼的生成細節和原理
二維碼又稱QR Code,QR全稱Quick Response,是一個近幾年來移動設備上超流行的一種編碼方式,它比傳統的Bar Code條形碼能存更多的信息,也能表示更多的數據類型:比如:字符,數字,日文,中文等等。這兩天學習了一下二維碼圖片生成的相關細節,覺得這個玩意就是一個密碼算法,在此寫一這篇文章,揭露一下。供好學的人一同學習之。
關於QR Code Specification,可參看下面附件的PDF:qr_code.pdf
基礎知識
首先,我們先說一下二維碼一共有40個尺寸。官方叫版本Version。Version1是21x21的矩陣,Version2是25x25的矩陣,Version3是29的尺寸,每增加一個version,就會增加4的尺寸,公式是:(V-1)*4+21(V是版本號)最高Version40,(40-1)*4+21=177,所以最高是177x177的正方形。
下面我們看看一個二維碼的樣例:
定位圖案
Position Detection Pattern是定位圖案,用於標記二維碼的矩形大小。這三個定位圖案有白邊叫Separators for Postion Detection Patterns。之所以三個而不是四個意思就是三個就可以標識一個矩形了。
Timing Patterns也是用於定位的。原因是二維碼有40種尺寸,尺寸過大了後需要有根標準線,不然掃瞄的時候可能會掃歪了。
Alignment Patterns只有Version2以上(包括Version2)的二維碼需要這個東東,同樣是為了定位用的。
功能性數據
Format Information存在於所有的尺寸中,用於存放一些格式化數據的。
Version Information在>=Version7以上,需要預留兩塊3x6的區域存放一些版本信息。
數據碼和糾錯碼
除了上述的那些地方,剩下的地方存放Data Code數據碼和Error Correction Code糾錯碼。
數據編碼
我們先來說說數據編碼。QR碼支持如下的編碼:
Numeric mode數字編碼,從0到9。如果需要編碼的數字的個數不是3的倍數,那麼,最後剩下的1或2位數會被轉成4或7bits,則其它的每3位數字會被編成10,12,14bits,編成多長還要看二維碼的尺寸(下面有一個表Table3說明了這點)
Alphanumeric mode字符編碼。包括0-9,大寫的A到Z(沒有小寫),以及符號$%*+–./:包括空格。這些字符會映射成一個字符索引表。如下所示:(其中的SP是空格,Char是字符,Value是其索引值)編碼的過程是把字符兩兩分組,然後轉成下表的45進制,然後轉成11bits的二進制,如果最後有一個落單的,那就轉成6bits的二進制。而編碼模式和字符的個數需要根據不同的Version尺寸編成9,11或13個二進制(如下表中Table3)
Byte mode,字節編碼,可以是0-255的ISO-8859-1字符。有些二維碼的掃瞄器可以自動檢測是否是UTF-8的編碼。
Kanji mode這是日文編碼,也是雙字節編碼。同樣,也可以用於中文編碼。日文和漢字的編碼會減去一個值。如:在0X8140to0X9FFC中的字符會減去8140,在0XE040到0XEBBF中的字符要減去0XC140,然後把前兩位拿出來乘以0XC0,然後再加上後兩位,最後轉成13bit的編碼。如下圖示例:
Extended Channel Interpretation(ECI)mode主要用於特殊的字符集。並不是所有的掃瞄器都支持這種編碼。
Structured Append mode用於混合編碼,也就是說,這個二維碼中包含了多種編碼格式。
FNC1mode這種編碼方式主要是給一些特殊的工業或行業用的。比如GS1條形碼之類的。
簡單起見,後面三種不會在本文中討論。
下面兩張表中,
Table2是各個編碼格式的「編號」,這個東西要寫在Format Information中。註:中文是1101
Table3表示了,不同版本(尺寸)的二維碼,對於,數字,字符,字節和Kanji模式下,對於單個編碼的2進制的位數。(在二維碼的規格說明書中,有各種各樣的編碼規範表,後面還會提到)
下面我們看幾個示例,
示例一:數字編碼
在Version1的尺寸下,糾錯級別為H的情況下,編碼:01234567
1.把上述數字分成三組:01234567
2.把他們轉成二進制:012轉成0000001100;345轉成010*******;67轉成1000011。
3.把這三個二進制串起來:000000110001010110011000011
4.把數字的個數轉成二進制(version1-H是10bits):8個數字的二進制是0000001000
5.把數字編碼的標誌0001和第4步的編碼加到前面:0001000000100000000011000101011001 1000011
示例二:字符編碼
在Version1的尺寸下,糾錯級別為H的情況下,編碼:AC-42
1.從字符索引表中找到AC-42這五個字條的索引(10,12,41,4,2)
2.兩兩分組:(10,12)(41,4)(2)
3.把每一組轉成11bits的二進制:
(10,12)10*45+12等於462轉成00111001110
(41,4)41*45+4等於1849轉成11100111001
(2)等於2轉成000010
4.把這些二進制連接起來:0011100111011100111001000010
5.把字符的個數轉成二進制(Version1-H為9bits):5個字符,5轉成000000101
6.在頭上加上編碼標識0010和第5步的個數編碼:00100000001010011100111011100111001 000010
結束符和補齊符
假如我們有個HELLO WORLD的字符串要編碼,根據上面的示例二,我們可以得到下面的編碼,
註:二維碼的糾錯碼主要是通過Reed-Solomon error correction(裡德-所羅門糾錯算法)來實現的。