摘要:在二維碼編碼的實(shí)現(xiàn)過(guò)程中,分析了QR Code二維條碼的結(jié)構(gòu)、編碼步驟、編碼原理和Reed-Solomon算法,并以數(shù)字模式為實(shí)例按照QR Code編碼原理直觀的描述了實(shí)現(xiàn)二維碼QR Code的編碼、糾錯(cuò)等功能。采用VC++的編程環(huán)境,通過(guò)對(duì)二維碼編碼程序反復(fù)測(cè)試,實(shí)現(xiàn)了二維碼QR Code的編碼程序設(shè)計(jì)。
關(guān)鍵詞:QR Code;二維碼;編碼;VC++;糾錯(cuò)
中圖分類號(hào):TP319 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2013)12-2904-05
條碼是采用二進(jìn)制概念的一種可印刷機(jī)器語(yǔ)言,具體地就是以“1”和“0”表示編碼的特定單元組合,以排列規(guī)則的圖形符號(hào)表示數(shù)據(jù)。條碼技術(shù)是在20世紀(jì)70年代初快速發(fā)展并得到廣泛應(yīng)用的一門技術(shù),早期的條碼稱為一維條碼,僅僅只是一種商品的標(biāo)識(shí),不含商品的任何描述。隨著現(xiàn)代高新技術(shù)和資料自動(dòng)收集技術(shù)的發(fā)展,最初的一維條碼技術(shù)已不能滿足人們的需求。于是在1987年David Allais博士提出了Code49的二維碼[1],這實(shí)際是把一維條碼的高度截短并按行堆積的一種多行連續(xù)型長(zhǎng)度可變條碼。如今常用的二維碼有:PDF417碼、QR Code碼、DataMatrix碼等等。
1 二維碼QR Code編碼原理
1.1 QR Code簡(jiǎn)述
1994年9月日本Denso公司開(kāi)發(fā)了一種矩陣式二維條碼符號(hào),即QR Code(Quick Response Code)快速響應(yīng)矩陣碼。QR Code除具有一維條碼及其它二維條碼所具有的優(yōu)點(diǎn)外,還具有識(shí)讀速度快、數(shù)據(jù)密度大、占用空間小的優(yōu)勢(shì)。QR Code基本結(jié)構(gòu)如圖1所示。
其中,位置探測(cè)圖形、位置探測(cè)圖形分隔符、定位圖形:用于對(duì)二維碼的定位,對(duì)每個(gè)QR碼來(lái)說(shuō),位置都是固定存在的,只是大小規(guī)格會(huì)有所差異;
校正圖形:規(guī)格確定,校正圖形的數(shù)量和位置也就確定了;
格式信息:表示改二維碼的糾錯(cuò)級(jí)別,分為L(zhǎng)、M、Q、H;
版本信息:即二維碼的規(guī)格,QR碼符號(hào)共有40種規(guī)格的矩陣(一般為黑白色),從21×21(版本1)如圖2,到177×177(版本40),每一版本符號(hào)比前一版本的每邊增加4個(gè)模塊。
數(shù)據(jù)和糾錯(cuò)碼字:實(shí)際保存的二維碼信息,和糾錯(cuò)碼字(用于修正二維碼損壞帶來(lái)的錯(cuò)誤)。
1.2 QR Code編碼
1.2.1 QR Code編碼步驟
QR Code編碼的主要步驟如下:
1)數(shù)據(jù)分析:確定編碼的字符類型,按相應(yīng)的字符集轉(zhuǎn)換成符號(hào)字符; 選擇糾錯(cuò)等級(jí),在規(guī)格一定的條件下,糾錯(cuò)等級(jí)越高其真實(shí)數(shù)據(jù)的容量越小。
2)數(shù)據(jù)編碼:將數(shù)據(jù)字符轉(zhuǎn)換為位流,每8位一個(gè)碼字,整體構(gòu)成一個(gè)數(shù)據(jù)的碼字序列。其實(shí)知道這個(gè)數(shù)據(jù)碼字序列就知道了二維碼的數(shù)據(jù)內(nèi)容。
3)糾錯(cuò)編碼:按需要將上面的碼字序列分塊,并根據(jù)糾錯(cuò)等級(jí)和分塊的碼字,產(chǎn)生糾錯(cuò)碼字,并把糾錯(cuò)碼字加入到數(shù)據(jù)碼字序列后面,成為一個(gè)新的序列。
4)構(gòu)造最終數(shù)據(jù)信息:在規(guī)格確定的條件下,將上面產(chǎn)生的序列按次序放入分塊中。
5)構(gòu)造矩陣:將探測(cè)圖形、分隔符、定位圖形、校正圖形和碼字模塊放入矩陣中。
6)掩摸:將掩摸圖形用于符號(hào)的編碼區(qū)域,使得二維碼圖形中的深色和淺色(黑色和白色)區(qū)域能夠比率最優(yōu)的分布,提高閱讀的可靠性。
7)格式和版本信息:生成格式和版本信息放入相應(yīng)區(qū)域內(nèi)。
1.2.2 Reed-Solomon算法
1960年Reed和Solomon共同提出了一種糾正隨機(jī)錯(cuò)誤和突發(fā)錯(cuò)誤的編碼,及Reed-Solomon(簡(jiǎn)稱RS)碼。RS碼是循環(huán)碼的一種,在伽羅華域GF(2m)中對(duì)數(shù)據(jù)位進(jìn)行編碼。若a∈GF(2m)對(duì)于糾正r個(gè)錯(cuò)誤符號(hào)的RS碼生成多項(xiàng)式[2]可表示為:
g(x)=(x+a)(x+a2)(x+a3)……(x+a2r) (1)
若原始信息的多項(xiàng)式為:m(x)=(a0+a1x+a2x2+……+ak-1xk-1),進(jìn)行RS編碼后的表達(dá)式[2]為:
d(x)=x2rm(x)+x2rm(x) mod g(x) (2)
其中:x2rm(x)是原始數(shù)據(jù)碼;x2rm(x) mod g(x)是糾錯(cuò)碼字部分。
1.2.3 編碼實(shí)例
為了能使QR Code生成有個(gè)直觀了解,下面舉例進(jìn)行說(shuō)明。
例如:以“01234567”這8個(gè)字符為例,采用數(shù)字模式,編碼一個(gè)版本號(hào)為1-M糾錯(cuò)等級(jí)的QR Code。
1)將輸入字符分為3個(gè)一組,剩下的2個(gè)或1個(gè)一組,且將每一組都轉(zhuǎn)換為10位或7位二進(jìn)制數(shù);
012:0000001100
345:0101011001
67 :1000011
得到二進(jìn)制序列為:0000001100 0101011001 1000011
2)將模式指示符和字符數(shù)依次放到上述序列前,并在最后放入結(jié)束符0000結(jié)果為:0001 0000001000 0000001100 0101011001 1000011 0000
3)將上述得到的二進(jìn)制數(shù)分為8位一組的碼字,并加入所需的填充位后得到的序列為:
00010000 00100000 00001100 01010110 01100001 10000000
4)因?yàn)榘姹?-M數(shù)據(jù)碼字容量為16個(gè)碼字,因此上面序列還需10個(gè)填充碼字,故用填充碼11101100和00010001依次進(jìn)行填充,結(jié)果為:
00010000 00100000 00001100 01010110 01100001 10000000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001
5)根據(jù)版本1-M需要10個(gè)糾錯(cuò)碼字對(duì)應(yīng)的生成多項(xiàng)式g(x)為:
g(x)=x10+a251x9+a67x8+a46x7+a61x6+a118x5+a70x4+a64x3+a94x2+a32x+a45
6.糾錯(cuò)等級(jí)M其掩膜圖形參考為:101,二進(jìn)制字符串為:00101,生成多項(xiàng)式為:x2+1.
QR碼中用BCH(15,5)碼糾錯(cuò),故將多項(xiàng)式次數(shù)提升(15-5)次方后為:x12+x10 被G(x)除后的結(jié)果是:(x10+x8+x5+x4+x2+x+1)x2+(x7+x6+x4+x3+x2)
把上面剩余多項(xiàng)式的系數(shù)字符串:001010011011100附加至格式信息數(shù)據(jù)串即可。
2 二維碼QR Code編碼實(shí)現(xiàn)
2.1 二維編碼對(duì)話框設(shè)計(jì)
在VC++中建立好工程后,就可以設(shè)計(jì)操作界面,類,變量,映射消息及及成員函數(shù)等。下圖是設(shè)計(jì)好的二維編碼對(duì)話框。
使用上面對(duì)話框,用戶可以選擇不同的糾錯(cuò)級(jí)別,掩膜號(hào),版本信息,并在二維條碼輸入?yún)^(qū)輸入不同信息后,在二維條碼顯示區(qū)就能顯示相應(yīng)的二維碼形狀,若輸入“01234567”顯示為圖4,若輸入“四川長(zhǎng)江職業(yè)學(xué)院”顯示為圖5。
2.2 二維編碼算法實(shí)現(xiàn)
根據(jù)前面的描述,下面給出了二維編碼程序流程示意圖。
圖6 二維編碼程序流程示意圖
根據(jù)上面的程序流程示意圖,下面是編碼算法實(shí)現(xiàn)的主要代碼。
EncodeData(int nLevel, int nVersion, BOOL bAutoExtent, int nMaskingNo, LPCSTR lpsSource, int ncSource)
{ int i, j;
m_nLevel = nLevel;//糾錯(cuò)級(jí)別
m_nMaskingNo = nMaskingNo;//掩膜號(hào)
int ncLength = ncSource > 0 ? ncSource : lstrlen(lpsSource);
if (ncLength == 0)
return FALSE;
// 獲取版本號(hào)
int nEncodeVersion = GetEncodeVersion(nVersion, lpsSource, ncLength);
if (nEncodeVersion == 0)
return FALSE;
if (nVersion == 0)
{m_nVersion = nEncodeVersion;}
else
{if (nEncodeVersion <= nVersion)
{m_nVersion = nVersion;}
else
{if (bAutoExtent)
m_nVersion = nEncodeVersion;
else
return FALSE; }}
// "0000" 加入終止符號(hào)
int ncDataCodeWord = QR_VersonInfo[m_nVersion].ncDataCodeWord[nLevel];
int ncTerminater = min(4, (ncDataCodeWord * 8) - m_ncDataCodeWordBit);
if (ncTerminater > 0)
m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, 0, ncTerminater);
//"11101100, 00010001"增加數(shù)據(jù)碼字
BYTE byPaddingCode = 0xec;
for (i = (m_ncDataCodeWordBit + 7) / 8; i < ncDataCodeWord; ++i)
{ m_byDataCodeWord[i] = byPaddingCode;
byPaddingCode = (BYTE)(byPaddingCode == 0xec ? 0x11 : 0xec);}
m_ncAllCodeWord = QR_VersonInfo[m_nVersion].ncAllCodeWord;
ZeroMemory(m_byAllCodeWord, m_ncAllCodeWord);
int nDataCwIndex = 0;
int ncBlock1 = QR_VersonInfo[m_nVersion].RS_BlockInfo1[nLevel].ncRSBlock;
int ncBlock2 = QR_VersonInfo[m_nVersion].RS_BlockInfo2[nLevel].ncRSBlock;
int ncBlockSum = ncBlock1 + ncBlock2;
int nBlockNo = 0;
//信息塊輸入
int ncDataCw1 = QR_VersonInfo[m_nVersion].RS_BlockInfo1[nLevel].ncDataCodeWord;
int ncDataCw2 = QR_VersonInfo[m_nVersion].RS_BlockInfo2[nLevel].ncDataCodeWord;
for (i = 0; i < ncBlock1; ++i)
{for (j = 0; j < ncDataCw1; ++j)
{m_byAllCodeWord[(ncBlockSum * j) + nBlockNo] = m_byDataCodeWord[nDataCwIndex++];}
++nBlockNo;}
for (i = 0; i < ncBlock2; ++i)
{for (j = 0; j < ncDataCw2; ++j)
{if (j < ncDataCw1)
{m_byAllCodeWord[(ncBlockSum * j) + nBlockNo] = m_byDataCodeWord[nDataCwIndex++];}
else
{m_byAllCodeWord[(ncBlockSum * ncDataCw1) + i] = m_byDataCodeWord[nDataCwIndex++];}}
++nBlockNo;}
// 糾錯(cuò)塊輸入
int ncRSCw1 = QR_VersonInfo[m_nVersion].RS_BlockInfo1[nLevel].ncAllCodeWord - ncDataCw1;
int ncRSCw2 = QR_VersonInfo[m_nVersion].RS_BlockInfo2[nLevel].ncAllCodeWord - ncDataCw2;
nDataCwIndex = 0;
nBlockNo = 0;
for (i = 0; i < ncBlock1; ++i)
{ZeroMemory(m_byRSWork, sizeof(m_byRSWork));
memmove(m_byRSWork, m_byDataCodeWord + nDataCwIndex, ncDataCw1);
GetRSCodeWord(m_byRSWork, ncDataCw1, ncRSCw1);//調(diào)用reed_solomon算法進(jìn)行糾錯(cuò)
for (j = 0; j < ncRSCw1; ++j)
{m_byAllCodeWord[ncDataCodeWord + (ncBlockSum * j) + nBlockNo] = m_byRSWork[j];}
nDataCwIndex += ncDataCw1;
++nBlockNo;}
for (i = 0; i < ncBlock2; ++i)
{ZeroMemory(m_byRSWork, sizeof(m_byRSWork));
memmove(m_byRSWork, m_byDataCodeWord + nDataCwIndex, ncDataCw2);
GetRSCodeWord(m_byRSWork, ncDataCw2, ncRSCw2); //調(diào)用reed_solomon算法進(jìn)行糾錯(cuò)
for (j = 0; j < ncRSCw2; ++j)
{m_byAllCodeWord[ncDataCodeWord + (ncBlockSum * j) + nBlockNo] = m_byRSWork[j];}
nDataCwIndex += ncDataCw2;
++nBlockNo;}
m_nSymbleSize = m_nVersion * 4 + 17;
FormatModule();
return TRUE;}
3 結(jié)論
實(shí)驗(yàn)實(shí)現(xiàn)了在錄入數(shù)據(jù)時(shí),能根據(jù)不同版本,糾錯(cuò)級(jí)別,掩膜號(hào)生成QR Code二維條碼。因二維條碼具有儲(chǔ)存量大、保密性高、追蹤性高、抗損性強(qiáng)、備援性大、成本便宜等特性,這些特性特別適用于表單如進(jìn)出口報(bào)單、安全保密如商業(yè)情報(bào)、追蹤如生產(chǎn)線零件自動(dòng)追蹤、證照如身份證、存貨盤點(diǎn)如物流中心等方面。
參考文獻(xiàn):
[1] 劉葦娜.QR Code二維條碼的編碼與圖像處理技術(shù)的研究[D].湖北大學(xué),2007.
[2] 馮漢祿,黃潁為,牛曉嬌,錢銀超.QR碼糾錯(cuò)碼原理及實(shí)現(xiàn)[J].計(jì)算機(jī)應(yīng)用,2011(6):40-42.
[3] 黃宏博,肖峻嶺,佟俐鵑.基于Reed-Solomon算法的QR碼糾錯(cuò)編碼[J].計(jì)算機(jī)工程,2003,29(1):93-95.
[4] 宋作玲,劉志海.基于VC++的QR Code條碼編程實(shí)現(xiàn)[J].山東科技大學(xué)學(xué)報(bào):自然科學(xué)版,2010,29(6):80-84.
[5] 曾子劍.基于QR二維碼編碼技術(shù)的研究與實(shí)現(xiàn)[D].電子科技大學(xué),2007.
[6] 許統(tǒng).手機(jī)二維碼在國(guó)內(nèi)的發(fā)展及應(yīng)用[J],電腦與信息技術(shù),2011,19(3):62-63.
[7] 楊平.QR Code條碼編解碼及應(yīng)用的研究[D].五邑大學(xué),2009.
[8] 蔡文婷.移動(dòng)端二維條碼圖像增強(qiáng)及應(yīng)用研究[D].浙江工業(yè)大學(xué),2008.