1. 程式人生 > >QR code二維碼簡介及Qrencode庫的移植與使用

QR code二維碼簡介及Qrencode庫的移植與使用

現在生活中,二維碼可以說是無處不在,微信掃碼支付,支付寶掃碼支付,就連貼小廣告的都帶上了二維碼了。之前一直想去了解一下,還是太懶了,就沒去,現在專案中需要用到這東西,正好藉此機會瞭解一下。

上網一查,原來二維碼的還有很多種。下表是一個簡單的介紹:


二維碼的優點突出,所以大有取代條形碼的趨勢,二維碼的特點:

1、高密度,容量大,可容納多達1850個大寫字母(字元)或2710個數字,支援最高1108個位元組的資料儲存,比一維碼資訊容量高几十倍。

2、 範圍廣,支援對圖片、聲音、文字、簽字、指紋等各類可以數字化資訊的編碼,還可以表示多種語言文字和影象資料。

3、 容錯能力強,具有糾錯功能,當二維碼因穿孔、汙損等引起區域性損壞時,照樣可以正常識別,損毀面積達

50%仍可恢復。

4、 成本低,易製作,持久耐用

本次開發使用的是QRcode,因為它目前使用的較為廣泛,微信支付,掃碼加好友等等都可以是QRcode

下面對QR Code做個詳細的瞭解:

QR Code碼,是由Denso公司於19949月研製的一種矩陣二維碼符號,它具有一維條碼及其它二維條碼所具有的資訊容量大、可靠性高、可表示漢字及圖象多種文字資訊、保密防偽性強等優點,是目前較為常用的二維條碼。

基本特性

編輯

符號規格

21×21模組(版本1-177×177 模組(版本40

(每一規格:每邊增加4個模組)

容量(指最大規格符號版本40-L級)

· 8位位元組資料

:2,953個字元

· 漢字資料 :1,817個字元

資料表示方法

深色模組表示二進位制“1”,淺色模組表示二進位制“0”

糾錯能力

· L級:約可糾錯7%的資料碼字

· M級:約可糾錯15%的資料碼字

· Q級:約可糾錯25%的資料碼字

· H級:約可糾錯30%的資料碼字

掩模(固有)

可以使符號中深色與淺色模組的比例接近11,使因相鄰模組的排列造成譯碼困難的可能性降為最小。

模式

1、數字模式(numeric mode ): 0001(數字09

2、混合字元模式(alphanumeric mode) : 0010(數字09;大寫字母AZ9個其他字元

:space ,$, %, *, +, -, ., /, :);

3、8bit byte mode: 0100

4、日本漢字(KANJI mode) : 1000

5、中國漢字(GB2312):1101GB 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/53020475

qrencode 本身是不依賴於 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!"

謝謝~