QR code二維碼簡介及Qrencode庫的移植與使用
現在生活中,二維碼可以說是無處不在,微信掃碼支付,支付寶掃碼支付,就連貼小廣告的都帶上了二維碼了。之前一直想去了解一下,還是太懶了,就沒去,現在專案中需要用到這東西,正好藉此機會瞭解一下。
上網一查,原來二維碼的還有很多種。下表是一個簡單的介紹:
二維碼的優點突出,所以大有取代條形碼的趨勢,二維碼的特點:
1、高密度,容量大,可容納多達1850個大寫字母(字元)或2710個數字,支援最高1108個位元組的資料儲存,比一維碼資訊容量高几十倍。
2、 範圍廣,支援對圖片、聲音、文字、簽字、指紋等各類可以數字化資訊的編碼,還可以表示多種語言文字和影象資料。
3、 容錯能力強,具有糾錯功能,當二維碼因穿孔、汙損等引起區域性損壞時,照樣可以正常識別,損毀面積達
4、 成本低,易製作,持久耐用等
本次開發使用的是QRcode,因為它目前使用的較為廣泛,微信支付,掃碼加好友等等都可以是QRcode。
下面對QR Code做個詳細的瞭解:
QR Code碼,是由Denso公司於1994年9月研製的一種矩陣二維碼符號,它具有一維條碼及其它二維條碼所具有的資訊容量大、可靠性高、可表示漢字及圖象多種文字資訊、保密防偽性強等優點,是目前較為常用的二維條碼。
基本特性
符號規格 |
21×21模組(版本1)-177×177 模組(版本40) |
(每一規格:每邊增加4個模組) |
|
容量(指最大規格符號版本40-L級) |
· 8位位元組資料 |
· 漢字資料 :1,817個字元 |
|
資料表示方法 |
深色模組表示二進位制“1”,淺色模組表示二進位制“0”。 |
糾錯能力 |
· L級:約可糾錯7%的資料碼字 |
· M級:約可糾錯15%的資料碼字 |
|
· Q級:約可糾錯25%的資料碼字 |
|
· H級:約可糾錯30%的資料碼字 |
|
掩模(固有) |
可以使符號中深色與淺色模組的比例接近1:1,使因相鄰模組的排列造成譯碼困難的可能性降為最小。 |
模式 |
1、數字模式(numeric mode ): 0001(數字0~9) 2、混合字元模式(alphanumeric mode) : 0010(數字0~9;大寫字母A~Z;9個其他字元 3、8bit byte mode: 0100 4、日本漢字(KANJI mode) : 1000 5、中國漢字(GB2312):1101(GB 2312對應的漢字和非漢字字元) |
為了美觀,可以在二維碼上新增一張logo圖片,一般放在中間。我在網上查了好久,沒有找到logo的大小和二維碼的等級和容錯性的關係,如果大家有找到的,請告知,謝謝,我這邊自己選擇了長寬是二維碼的20%,測試不影響識別。
編碼階段:
在網上找了一個第三方的庫,qrencode,提供了製作二維碼的API,介面很簡單,
externQRcode*QRcode_encodeString(constchar*string,intversion,QRecLevellevel,QRencodeModehint,intcasesensitive);
這個API可以直接設定要編碼的字串內容,以及對二維碼的設定,如版本(即大小等級1~40)、容錯等級、模式等,返回的是一個結構體指標,QRcode,
typedefstruct{
intversion;///< version of the symbol
intwidth;///< width of the symbol
unsignedchar*data;///< symbol data
}QRcode;
它的資料data就是二維碼的內容,1對應深色塊,0對應淺色塊。藉助一些其他的畫圖的API就可以繪製出二維碼。哭的詳細介紹請參考:點選開啟連結
我使用的是QT+VS 和QT+Linux,做的是嵌入式開發,所以需要涉及到一些交叉編譯等。
這個是我開始編譯成動態庫遇到的一些問題。
靜態庫的編譯參照了 http://blog.csdn.net/liyuanbhu/article/details/44647139 博主的配置,在此感謝。
將博主的一些東西搬過來,從而讓本文更加完整,下面是編譯windows下的靜態庫的過程。
建立一個 win32 專案,選擇生成靜態庫,不使用預編譯頭。將 qrencode 的原始檔(.c 和 .h)全部拷到vc 的專案目錄中,除了 qrenc.c 。編譯 qrencode 時還需要有個 config.h 檔案(原始碼中的config.h.in檔案修改成config.h),這個檔案主要是配置庫中的一些巨集開關,可以用我下面提供的這個。
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if using pthread is enabled. */
#undef HAVE_LIBPTHREAD
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Major version number */
#define MAJOR_VERSION 3
/* Micro version number */
#define MICRO_VERSION 4
/* Minor version number */
#define MINOR_VERSION 4
/* Name of package */
#define PACKAGE "qrencode"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "QRencode"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "QRencode 3.4.4"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "qrencode"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "3.4.4"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "3.4.4"
#define inline
/* Define to 'static' if no test programs will be compiled. */
#define __STATIC static
/* #undef WITH_TESTS */
然後在專案屬性中新增預處理定義:HAVE_CONFIG_H(專案->屬性->配置屬性->C/C++->前處理器->前處理器定義)
config.h 中有一行:#define inline
是因為rscode.c 檔案中有個modnn的定義如下:
static inline int modnn(RS *rs, int x){
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}
在用VS2012編譯的時候,在split.c檔案中,strdup編譯不過,提示 error C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup. See online help for details. 將strdup改成_strdup,具體參考我的部落格:http://blog.csdn.net/u010977122/article/details/53020475qrencode 本身是不依賴於 libpng 庫的。所以不存在什麼缺少 png.h 的問題。按照本文介紹的方法按部就班的做就能生成靜態庫,不存在任何問題。編譯時一定要排除 qrenc.c 這個檔案。這個檔案是 qrencode 的一個使用例子,與這個庫本身無關。
生成了libqrencode.a的一個靜態庫,再配qrencode.h這個標頭檔案,就可以在專案中使用了。
在QT中使用的具體程式碼如下:void HQrencodePCtrl::PaintQRcode::draw(QPainter &painter, int width, int height)
{
QColor foreground(Qt::black);
painter.setBrush(foreground);
const int qr_width = qr->width > 0 ? qr->width : 1;
double scale_x = width / qr_width;
double scale_y = height / qr_width;
for( int y = 0; y < qr_width; y ++)
{
for(int x = 0; x < qr_width; x++)
{
unsigned char b = qr->data[y * qr_width + x];
if(b & 0x01)
{
QRectF r(int(x * scale_x), int(y * scale_y), int(scale_x), int(scale_y));
painter.drawRects(&r, 1);
}
}
}
if(bhavelogo) //新增Logo的圖片,繪製在二維碼的中間
{
QPixmap picture(logoaddr.c_str());
int logoWidth = width*0.2;
int logoHeight = height * 0.2;
painter.drawPixmap(width/2-logoWidth/2,height/2-logoHeight/2,logoWidth,logoHeight,picture);
}
}
<pre name="code" class="cpp">void HQrencodePCtrl::PaintQRcode::setString(HString str)
{
priv_string = str;
if(qr != NULL)
{
QRcode_free(qr);
}
qr = QRcode_encodeString(priv_string.c_str(),
1,
QR_ECLEVEL_L,
QR_MODE_8,
1);
update();
}
void HQrencodePCtrl::PaintQRcode::paint(QPainter *painter)
{
QColor background(Qt::white);
painter->setBrush(background);
painter->setPen(Qt::NoPen);
//painter->drawRect(0, 0, width(), height());
if(qr != NULL)
{
int paintWidth = int(width()/qr->width)*qr->width ;
int paintHeight = int(height()/qr->width)*qr->width;
painter->drawRect(0, 0, paintWidth, paintHeight);
draw(*painter, paintWidth,paintHeight);
}
}
在linux下編譯成庫,主要是寫Makefile 檔案,除了將strdup改成_strdup再改回去,其他不變。下面是我的makefile檔案:
TARGET = libqrencode
TARGET_DIR = ../../../lib/linux/debug/
#OBJ_DIR = ./objs
#$(CC) -o $(TARGET_DIR)/$(TARGET) $(OBJ_FILES) $(LDFLAGS)
INCLUDE = -I../../../src/ -I../../../inc/
SOURCES = ../../../src/bitstream.c ../../../src/mask.c ../../../src/mmask.c ../../../src/mqrspec.c ../../../src/qrencode.c ../../../src/qrinput.c ../../../src/qrspec.c ../../../src/rscode.c ../../../src/split.c
LIBS = -lpthread
OBJ_FILES = $(patsubst %.c, %.o, $(SOURCES))
CC = arm-poky-linux-gnueabi-g++ -march=armv7-a -mthumb-interwork -mfloat-abi=hard -mfpu=neon -mtune=cortex-a9 --sysroot=/opt/poky/1.7/sysroots/cortexa9hf-vfp-neon-poky-linux-gnueabi -std=c++11 -ggdb
AR = arm-poky-linux-gnueabi-ar #這裡將編譯器替換成自己需要的編譯器
#CC = gcc
#AR = ar
LDFLAGS += $(LIBS)
CPPFLAGS += $(INCLUDE)
all: check_env compile link
check_env:
@echo "[$(TARGET)]: Build Start..."
@mkdir -p $(TARGET_DIR)
compile: $(OBJ_FILES)
link:
@echo "[$(TARGET)]: Linking ..."
@$(AR) rcs $(TARGET_DIR)/$(TARGET).a $(OBJ_FILES)
@echo "[$(TARGET)]: Build done!"
#complie step 1:
$(OBJ_FILES): %.o: %.c
@echo "[$(TARGET)]: Compiling $(notdir $^) ..."
@$(CC) -DHAVE_CONFIG_H=1 -fPIC -c $(CPPFLAGS) $< -o [email protected] #這裡在編譯的時候加上<span style="font-family: 'Times New Roman';">HAVE_CONFIG_H=1的巨集定義</span>
clean:
@rm -rf $(OBJ_FILES) $(TARGET_DIR)/$(TARGET).a
@echo "[$(TARGET)]: Clean Finish!"
謝謝~