摘自並整理:http://blog.chinaunix.net/uid-22670933-id-5781511.html
現在生活中,二維碼可以說是無處不在,微信掃碼支付,支付寶掃碼支付,就連貼小廣告的都帶上了二維碼了。之前一直想去了解一下,還是太懶了,就沒去,現在項目中需要用到這東西,正好借此機會了解一下。
上網一查,原來二維碼的還有很多種。下表是一個簡單的介紹:
二維碼的優點突出,所以大有取代條形碼的趨勢,二維碼的特點:
1、高密度,容量大,可容納多達1850個大寫字母(字符)或2710個數字,支持最高1108個字節的數據存儲,比一維碼信息容量高幾十倍。
2、 范圍廣,支持對圖片、聲音、文字、簽字、指紋等各類可以數字化信息的編碼,還可以表示多種語言文字和圖像數據。
3、 容錯能力強,具有糾錯功能,當二維碼因穿孔、污損等引起局部損壞時,照樣可以正常識別,損毀面積達50%仍可恢復。
4、 成本低,易制作,持久耐用等
本次開發使用的是QRcode,因為它目前使用的較為廣泛,微信支付,掃碼加好友等等都可以是QRcode。
下面對QR Code做個詳細的了解:
QR Code碼,是由Denso公司於1994年9月研制的一種矩陣二維碼符號,它具有一維條碼及其它二維條碼所具有的信息容量大、可靠性高、可表示漢字及圖象多種文字信息、保密防偽性強等優點,是目前較為常用的二維條碼。
基本特性
符號規格 |
21×21模塊(版本1)-177×177 模塊(版本40) |
(每一規格:每邊增加4個模塊) |
|
容量(指最大規格符號版本40-L級)
|
· 8位字節數據 :2,953個字符 |
· 漢字數據 :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個其他字符:space ,$, %, *, +, -, ., /, :); 3、8bit byte mode: 0100 4、日本漢字(KANJI mode) : 1000 5、中國漢字(GB2312):1101(GB 2312對應的漢字和非漢字字符) |
為了美觀,可以在二維碼上添加一張logo圖片,一般放在中間。我在網上查了好久,沒有找到logo的大小和二維碼的等級和容錯性的關系,如果大家有找到的,請告知,謝謝,我這邊自己選擇了長寬是二維碼的20%,測試不影響識別。
qrencode下載地址https://fukuchi.org/works/qrencode/
編碼階段:
在網上找了一個第三方的庫,qrencode,提供了制作二維碼的API,接口很簡單,
extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
這個API可以直接設置要編碼的字符串內容,以及對二維碼的設置,如版本(即大小等級1~40)、容錯等級、模式等,返回的是一個結構體指針,QRcode,
typedef struct {
int version; ///< version of the symbol
int width; ///< width of the symbol
unsigned char *data; ///< symbol data
} QRcode;
它的數據data就是二維碼的內容,1對應深色塊,0對應淺色塊。借助一些其他的畫圖的API就可以繪制出二維碼。哭的詳細介紹請參考:點擊打開鏈接
我使用的是MTK6261A做的是嵌入式開發,所以需要涉及到一些交叉編譯等。
由於qrencode 在我們項目中作為一個第三方庫,只需要它的基礎功能,后面不會持續去更新,所以,決定將其編譯成靜態庫。如果想編譯成動態庫,可以參考http://blog.csdn.net/u010977122/article/details/52959098
這個是我開始編譯成動態庫遇到的一些問題。
靜態庫的編譯參照了 http://blog.csdn.net/liyuanbhu/article/details/44647139 博主的配置,在此感謝。
將博主的一些東西搬過來,從而讓本文更加完整,下面是編譯windows下的靜態庫的過程。
將下載下來的qrencode-4.0.2.tar.gz解壓縮,直接./configure;make,編譯后生成config.h
將 qrencode 的源文件(.c 和 .h)全部拷出來,除了 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 <dlfcn.h> header file. */ #define HAVE_DLFCN_H 1 /* Define if you have the iconv() function and it works. */ /* #undef HAVE_ICONV */ /* Define to 1 if you have the <inttypes.h> header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if using pthread is enabled. */ #define HAVE_LIBPTHREAD 0 /* Define to 1 if you have the <memory.h> header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if using libpng is enabled. */ #define HAVE_PNG 0 /* Define to 1 if using SDL is enabled. */ /* #undef HAVE_SDL */ /* 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 `strdup' function. */ #define HAVE_STRDUP 0 /* 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 <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 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Major version number */ #define MAJOR_VERSION 4 /* Micro version number */ #define MICRO_VERSION 2 /* Minor version number */ #define MINOR_VERSION 0 /* 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 4.0.2" /* 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 "4.0.2" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "4.0.2" /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to 'static' if no test programs will be compiled. */ #define STATIC_IN_RELEASE static /* #undef WITH_TESTS */
新寫一個頭文件,把代碼弄成平台無關性。
#ifndef __MY_QRCODE_H__ #define __MY_QRCODE_H__ #ifdef __cplusplus extern "C" { #endif #define MY_free free #define MY_malloc malloc #define MY_calloc(n, s) malloc(n*s) #define MY_re_malloc(a, b, c) realloc(a, b + c) #if IS_SUPPORT_TFT_SCREEN #define MY_DELETE_THIS (0) #define HAVE_CONFIG_H (1) #ifndef EINVAL #define EINVAL 22 #endif #endif #ifdef __cplusplus } #endif #endif
下面是自己寫的Makefile
all:my_qrcode.so gcc bitstream.c mask.c mmask.c mqrspec.c qrencode.c qrinput.c qrspec.c rsecc.c split.c -fPIC -shared -o $@ strip $@
qrencode 本身是不依賴於 libpng 庫的。所以不存在什么缺少 png.h 的問題。按照本文介紹的方法按部就班的做就能生成靜態庫,不存在任何問題。編譯時一定要排除qrenc.c 這個文件。這個文件是 qrencode 的一個使用例子,與這個庫本身無關。
生成了libqrencode.a的一個靜態庫,再配qrencode.h這個頭文件,就可以在項目中使用了。
qrenc.c 這個文件是 qrencode 的一個使用例子,與這個庫本身無關。現在寫一個庫的使用例子:
QRcode *MY_QRCODE_encode(const unsigned char *intext, int length) { QRcode *code; code = QRcode_encodeString((char *)intext, version, level, hint, casesensitive); return code; } static int my_writeSVG(const QRcode *qrcode) { unsigned char *row, *p; int x, y; /* Write data */ p = qrcode->data; for(y = 0; y < qrcode->width; y++) { row = (p+(y*qrcode->width)); if( !rle ) { /* no RLE */ for(x = 0; x < qrcode->width; x++) { printf(" %d ", *(row+x)&0x1 ); } printf("\r\n"); } } return 0; } void my_draw_qrcode(const unsigned char *intext, int length) { QRcode *qrcode = NULL; qrcode = MY_QRCODE_encode(intext, length); if(qrcode == NULL) { return; } feitian_writeSVG(qrcode); QRcode_free(qrcode);
qrcode = NULL; } int main(int argc, char *argv[]) { my_draw_qrcode(argv[1], strlen(argv[1])); return 0; }