大概刚做 Android 开发的时候就做过二维码扫描, 那时候懂的东西少, 就搜出来了 ZXing 和 Zbar 两个库. ZXing 是纯 Java 代码实现的, 适用于 Android 平台; Zbar 是 C 实现的, 可以供很多语言和平台使用, 比如 Java,iOS 平台, Android 平台, Python 等等. 很明显 Zbar 的识别率和速度都是明显快于 ZXing 的, 但是无奈那时候不会编译 Zbar, 只好下载了 ZXing, 但是由于当时技术能力不足, 对于 ZXing 自定义剪切框也做不出来, 只好下载了别人编译好的 Zbar, 可能由于别人修改了代码或者编译的不是很完整, 后期 bug 层出, 废了好大劲才完善好.
后来一直没有机会学习二维码扫描, 直到前几天需要给我们平台的 APP 加上了二维码扫描功能, 我决定使用 ZBar, 于是我完整的编译了一次, 今天把这个过程记录下来, 希望可以帮助到需要的同学.
比如微信使用的是 ZXing, 但是我肯定的说他们修改了不少源码, 而且有很多地方应该改成了 jni 实现, 所以微信的识别速率和准确率是相当高的, 不过今天我编译后的封装也是秒秒钟就可以识别.
因为 Zbar 是基于 LGPL-2.1 开源的, 因此我基于 LGPL-2.1 协议, 我把一个完整的项目源码和 sample 放到 Github 上了, 提供直接调用 zbar 的识别 byte[] 数据的功能和调用相机识别二维码的功能:
https://github.com/yanzhenjie/android-zbar-sdk
特别声明: 本文已经修复了 zbar 识别中文乱码的问题!!!
编译 Zbar
在正式编译之前要注意: 编译 Zbar 需要先编译 libiconv, 编译 libiconv 需要 linux 环境, 需要用到 gcc. 如果你没有 linux 环境也没有关系, 我已经提供了编译好的 libiconv.
其实在 Zbar 的官网也可以下载到他们已经编译好的 so 和 jar, 但是 so 文件他们只提供了 armeabi,armeabi-v7a,x86 平台:
https://sourceforge.net/projects/zbar/files/?source=navbar
所以我就抛弃了提供的编译包, 自己编译了, 下面是步骤.
首先在 Zbar 的开源主页下载 Zbar 源码:
https://github.com/ZBar/ZBar
顺便在开源主页点开 android 文件夹, 发现编译 Zbar 需要 libiconv, 接下来下载 libiconv:
http://www.gnu.org/software/libiconv
对于 libiconv 我是下载的在 2017-02-02 时发布的最新版 1.15.
一, 编译 libiconv
如果你没有 linux 环境编译 libiconv, 那么你可以在这里下载我已经编译好的 libiconv1.15:
http://download.csdn.net/detail/yanzhenjie1003/9833225 , 下好好文件后, 你就可以直接跳过这一节, 看下面 Zbar 和 libiconv 一起编译了.
如果你有 linux 环境可以编译 libiconv, 那么继续往下看.
下载好 libiconv 后, 进入 libiconv 文件夹, 如果报权限错误进不去的话执行 sudo chmod 777 -R libiconv 就可以了:
进来后先执行:./configure, 如果提示没权限那么执行: sudo chmod 777 configure, 然后重新执行 /.configure 即可.
等./configure 执行完后再执行 make 命令即可完成编译
编译时可能遇到以下错误:
1,configure: error: no acceptable C compiler found in $PATH
这个是说你没有安装 gcc, 安装 gcc 后再次执行未完成命令即可.
二, Zbar 和 libiconv 一起编译
libiconv 编译完成了, 接下来把 Zbar 和 libiconv 放到一起, 编译出我们需要的 so 文件.
把刚才编译好的 libiconv 放入我们项目的 jni 文件夹.
解压刚才下载好的 Zbar, 首先把 Zbar 的头文件所在文件夹 zbar/include 放入我们项目的 jni 文件夹下.
把 Zbar 对 java 的接口文件 zbarjni.c 放入我们项目的 jni 文件夹, zbrjni.c 在 zbar/java 文件夹下.
把 Zbar 的核心库文件所在的文件夹 zbar/zbar 放到我们项目的 jni 文件夹下.
把 Zbar 编译时需要的 Android.mk,Applicaiton.mk,config.h 从 zbar\android\jni 下拷贝到我们项目的 jni 文件夹下.
此时我们项目的 jni 文件夹是这样的:
理论上现在可以开始编译了吧, 但是呢因为我们改动了 zbar 的文件夹结构, 所以我们要对 Android.mk 进行改动, 主要改的是文件夹路径和文件路径, 修改后的 Android.mk 的内容如下:
MY_LOCAL_PATH :=$(call my-dir)#libiconvinclude $(CLEAR_VARS)LOCAL_PATH :=$(MY_LOCAL_PATH)LOCAL_MODULE := libiconvLOCAL_CFLAGS :=\-Wno-multichar\-D_ANDROID\-DLIBDIR="c"\-DBUILDING_LIBICONV\-DBUILDING_LIBCHARSET\-DIN_LIBRARYLOCAL_SRC_FILES :=\libiconv-1.15/lib/iconv.c\libiconv-1.15/libcharset/lib/localcharset.c\libiconv-1.15/lib/relocatable.cLOCAL_C_INCLUDES :=\$(LOCAL_PATH)/libiconv-1.15/include\$(LOCAL_PATH)/libiconv-1.15/libcharset\$(LOCAL_PATH)/libiconv-1.15/libcharset/includeinclude$(BUILD_SHARED_LIBRARY)LOCAL_LDLIBS := -llog -lcharset#-----------------------------------------------------#libzbarinclude $(CLEAR_VARS)LOCAL_PATH :=$(MY_LOCAL_PATH)LOCAL_MODULE := zbarLOCAL_SRC_FILES :=\zbarjni.c\zbar/img_scanner.c\zbar/decoder.c\zbar/image.c\zbar/symbol.c\zbar/convert.c\zbar/config.c\zbar/scanner.c\zbar/error.c\zbar/refcnt.c\zbar/video.c\zbar/video/null.c\zbar/decoder/code128.c\zbar/decoder/code39.c\zbar/decoder/code93.c\zbar/decoder/codabar.c\zbar/decoder/databar.c\zbar/decoder/ean.c\zbar/decoder/i25.c\zbar/decoder/qr_finder.c\zbar/qrcode/bch15_5.c\zbar/qrcode/binarize.c\zbar/qrcode/isaac.c\zbar/qrcode/qrdec.c\zbar/qrcode/qrdectxt.c\zbar/qrcode/rs.c\zbar/qrcode/util.cLOCAL_C_INCLUDES :=\$(LOCAL_PATH)/include\$(LOCAL_PATH)/zbar\$(LOCAL_PATH)/libiconv-1.15/includeLOCAL_SHARED_LIBRARIES := libiconvinclude$(BUILD_SHARED_LIBRARY)
然后在 Application.mk 中填写你要编译的平台, 如果想全部编译:
APP_ABI := all
如果要指定编译某几个平台, 把平台名称依次空格隔开写上即可:
APP_ABI := armeabi armeabi-v7a x86 x86_64 mips mips_64 arm64_v8a
此时我们用命令行进入项目的 jni 文件夹的父母路, 比如一般 jni 情况下 jni 文件夹位于 ProjectName/ModuleName/src/main/jni, 那么我们就进入这个 main, 然后此时执行 ndk-build 进行编译.
如果提示没有 ndk-build 这个命令, 那么你需要从 http://developer.android.com/ 下载 ndk 并且在电脑上配置 PATH.
等 ndk-build 执行完后会在 libs 下生成所有平台的 so 文件夹, 文件夹里面是需要的 libiconv 和 zbar 的 so 文件.
编译 Zbar 和 libiconv 时遇到的错误解决
编译过程中可能发现如下错误, 请按照修改方案修改即可.
1,libiconv-1.15/jni/libcharset/lib/localcharset.c:51:24: error: langinfo.h: No such file or directory
打开 libiconv-1.15/libcharset/config.h 文件, 搜索 #define HAVE_LANGINFO_CODESET, 大概在 14 行, 把这行注释了即可:
/*#define HAVE_LANGINFO_CODESET 1 */
2,...c undeclaired...
打开 libiconv-1.15/libcharset/lib/localcharset.c, 搜索到函数 get_charset_aliases(), 大概在 124 行.
大概在 195 行左右, 有一个 int c;(没有的话你可以搜索 int c;), 把这个一行代码移动到 get_charset_aliases() 开头:
移动之前:
移动之后:
zbar 的 jar 包
现在 so 文件有了, 剩下的就是怎么调用 so 中的函数来识别条码 / 二维码了, 首先把 zbar/java 下在 net.sourceforge.zbar 包和里边的 java 文件拷贝到你的项目的 java 目录下, 大概结构如下:
当然你也像这样使用源码, 也可以把这几个类打包成 jar 包.
调用 Zbar 识别二维码
现在全部都编译好了, jar 文件也有了, 我们可以调用 jar 中封装的方法来识别二维码了:
byte[] imageData = ...;Image barcode =newImage(size.width, size.height,"Y800");barcode.setData(imageData);// 指定二维码在图片中的区域, 也可以不指定, 识别全图.// barcode.setCrop(startX, startY, width, height);String qrCodeString =null;intresult = mImageScanner.scanImage(barcode);if(result !=0) { SymbolSet symSet = mImageScanner.getResults();for(Symbol sym : symSet) qrCodeString = sym.getData();}if(!TextUtils.isEmpty(qrCodeString)) {// 成功识别二维码, qrCodeString 就是数据.}
如何和相机结合使用等复杂操作这里不再说了, 一个完整的项目我放到 Github 上了:
https://github.com/yanzhenjie/android-zbar-sdk
来源: http://www.jianshu.com/p/6c3681727dc4