很多手机app条形码应用都使用了ZXing和ZBar两个开源条形码SDK。那么从检测速度和检测率看哪个更出色呢?ZXing用Java实现,ZBar用C/C++实现,为了确保公平,这里用JNI封装ZBar,用Java写测试。
参考原文:How to Benchmark Barcode SDK Performance – ZXingvsZBar
作者:Desmond Shaw
翻译:yushulx
SDK下载
ZXing Source code
https://github.com/zxing/zxing
ZBar Source Code
ZBar Windows Installer
http://sourceforge.net/projects/zbar/files/zbar/
如何使用Java解码TIFF文件
通过Java SDK中的ImageIO,我们可以解码很多图片格式,比如JPEG,PNG,BMP。但是TIFF是不支持的。实际使用的时候,经常会用到TIFF文件读取条形码。Oracle官方提供了Java Advanced Imaging (JAI)来支持TIFF。
JAI下载
照理说Oracle的官网是应该提供JAI的下载链接的。但是很奇怪的是打开之后都是404错误。在网上搜了一圈,找到了一个可用链接:http://www.java2s.com/Code/Jar/j/Downloadjaicore113jar.htm。使用的时候需要下载jai_codec-1.1.3.jar和jai_core-1.1.3.jar。这里是一个把TIFF读到int[]的例子:
File file = new File(fileName); RenderedImage tiff = JAI.create("tiffload", fileName); BufferedImage image = PlanarImage.wrapRenderedImage(tiff).getAsBufferedImage(); int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth();
使用ZXing读取图片中的多个条形码
ZXing中的MultiFormatReader是用来读取一个条形码的,要读取多个条形码,需要把它放到GenericMultipleBarcodeReader中:
RGBLuminanceSource source = new RGBLuminanceSource(image.getWidth(), image.getHeight(), pixels); bitmap = new BinaryBitmap(new HybridBinarizer(source)); Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>(); hints.put(DecodeHintType.TRY_HARDER, null); Collection<BarcodeFormat> formats = new ArrayList<>(); formats.add(BarcodeFormat.QR_CODE); formats.add(BarcodeFormat.CODABAR); formats.add(BarcodeFormat.CODE_39); formats.add(BarcodeFormat.CODE_93); formats.add(BarcodeFormat.CODE_128); formats.add(BarcodeFormat.EAN_8); formats.add(BarcodeFormat.EAN_13); formats.add(BarcodeFormat.ITF); formats.add(BarcodeFormat.UPC_A); formats.add(BarcodeFormat.UPC_E); formats.add(BarcodeFormat.UPC_EAN_EXTENSION); hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); MultiFormatReader reader = new MultiFormatReader(); // read multi barcodes GenericMultipleBarcodeReader multiReader = new GenericMultipleBarcodeReader( reader); try { Result[] results = multiReader.decodeMultiple(bitmap, hints); System.out.println(ZXING + TIME_COST + ((System.nanoTime() - start) / 1000000) + MS); if (results != null) { for (Result result : results) { System.out.println(ZXING + TYPE + result.getBarcodeFormat() + VALUE + result.getText()); } } } catch (NotFoundException e) { e.printStackTrace(); return; }
ZBar JNI
要用JNI封装ZBar,最简单的方法就是参考自带的例子scan_image.cpp。把main函数改成JNI的接口就行了,在底层获取数据之后返回给Java层:
#include <iostream> #include <Magick++.h> #include <zbar.h> #include <jni.h> #define STR(s) #s using namespace std; using namespace zbar; #ifndef DEBUG #define DEBUG(...) printf(__VA_ARGS__) #endif extern "C" { JNIEXPORT jobjectArray JNICALL Java_com_dynamsoft_zbar_ZBarReader_decode(JNIEnv *env, jobject obj, jstring fileName); } JNIEXPORT jobjectArray JNICALL Java_com_dynamsoft_zbar_ZBarReader_decode(JNIEnv *env, jobject obj, jstring fileName) { const char *pszFileName = env->GetStringUTFChars(fileName, 0); #ifdef MAGICK_HOME // http://www.imagemagick.org/Magick++/ // under Windows it is necessary to initialize the ImageMagick // library prior to using the Magick++ library Magick::InitializeMagick(MAGICK_HOME); #endif // create a reader ImageScanner scanner; // configure the reader scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1); // obtain image data Magick::Image magick(pszFileName); // read an image file int width = magick.columns(); // extract dimensions int height = magick.rows(); Magick::Blob blob; // extract the raw data magick.modifyImage(); magick.write(&blob, "GRAY", 8); const void *raw = blob.data(); // wrap image data Image image(width, height, "Y800", raw, width * height); // scan the image for barcodes int n = scanner.scan(image); // find java class jclass clsZBarResult = env->FindClass("com/dynamsoft/zbar/ZBarResult"); // create java array int data_length = 0; for (Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol) { ++data_length; } jobjectArray clsZBarResultArray = env->NewObjectArray(data_length, clsZBarResult, 0); int iIndex = 0; // extract results for (Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol) { // do something useful with results //cout << "ZBR Type: " << symbol->get_type_name() // << ", Value \"" << symbol->get_data() << ‘"‘ << endl; // save result to java array jmethodID init = env->GetMethodID(clsZBarResult, "<init>", "()V"); jobject clsZBarResultObj = env->NewObject(clsZBarResult, init); jfieldID jType = env->GetFieldID(clsZBarResult, "mType", "Ljava/lang/String;"); jfieldID jValue = env->GetFieldID(clsZBarResult, "mValue", "Ljava/lang/String;"); env->SetObjectField(clsZBarResultObj, jType, env->NewStringUTF(symbol->get_type_name().c_str())); env->SetObjectField(clsZBarResultObj, jValue, env->NewStringUTF(symbol->get_data().c_str())); env->SetObjectArrayElement(clsZBarResultArray, iIndex, clsZBarResultObj); ++iIndex; } // clean up image.set_data(NULL, 0); // release string env->ReleaseStringUTFChars(fileName, pszFileName); return clsZBarResultArray; }
这里你会需要用到ImageMagick x86版本,下载地址:http://www.imagemagick.org/script/binary-releases.php。
相关的Java类如下:
ZBarReader.java
package com.dynamsoft.zbar; import com.dynamsoft.utils.BaseReader; public class ZBarReader extends BaseReader { static { System.loadLibrary("zbarjni"); } public void testZBar(String fileName) { long start = System.nanoTime(); ZBarReader reader = new ZBarReader(); ZBarResult[] results = (ZBarResult[])reader.decode(fileName); System.out.println(ZBAR + TIME_COST + ((System.nanoTime() - start) / 1000000) + MS); if (results != null && results.length > 0) { mCount += 1; for (ZBarResult result : results) { System.out.println(ZBAR + TYPE + result.mType + VALUE + result.mValue); } } } @Override public int getCount() { // TODO Auto-generated method stub return super.getCount(); } public native Object[] decode(String fileName); }
ZBarResult.java
package com.dynamsoft.zbar; public class ZBarResult { public String mType; public String mValue; }
性能PK
找一些数据集来测试。多条形码测试可以使用Dynamsoft的测试数据https://github.com/Dynamsoft/Dynamsoft-Barcode-Reader/tree/master/Images,单条形码可以使用ZXing的数据https://github.com/zxing/zxing/tree/master/core/src/test/resources。这里用ZXing的二维码数据https://github.com/zxing/zxing/tree/master/core/src/test/resources/blackbox/qrcode-1来做一个测试对比,结果如下:
F:\resources\blackbox\qrcode-1\1.png ZXI Time cost: 122ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 33ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\10.png ZXI Time cost: 66ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 28ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\11.png ZXI Time cost: 53ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 29ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\12.png ZXI Time cost: 71ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 29ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\13.png ZXI Time cost: 84ms ZXI Type: QR_CODE, value: http://google.com/gwt/n?u=bluenile.com ZBA Time cost: 27ms ZBA Type: QR-Code, value: http://google.com/gwt/n?u=bluenile.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\14.png com.google.zxing.NotFoundException ZBA Time cost: 32ms ZBA Type: QR-Code, value: http://google.com/gwt/n?u=bluenile.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\15.png ZXI Time cost: 90ms ZXI Type: QR_CODE, value: http://google.com/gwt/n?u=bluenile.com ZBA Time cost: 34ms ZBA Type: QR-Code, value: http://google.com/gwt/n?u=bluenile.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\16.png ZXI Time cost: 77ms ZXI Type: QR_CODE, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ZBA Time cost: 35ms ZBA Type: QR-Code, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\17.png ZXI Time cost: 82ms ZXI Type: QR_CODE, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ZBA Time cost: 32ms ZBA Type: QR-Code, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\18.png ZXI Time cost: 80ms ZXI Type: QR_CODE, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ZBA Time cost: 35ms ZBA Type: QR-Code, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\19.png ZXI Time cost: 64ms ZXI Type: QR_CODE, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ZBA Time cost: 28ms ZBA Type: QR-Code, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\2.png ZXI Time cost: 61ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 28ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\20.png ZXI Time cost: 55ms ZXI Type: QR_CODE, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ZBA Time cost: 30ms ZBA Type: QR-Code, value: Sean Owen [email protected] 917-364-2918 http://awesome-thoughts.com ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\3.png ZXI Time cost: 56ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 29ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\4.png ZXI Time cost: 70ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 28ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\5.png ZXI Time cost: 64ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 28ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\6.png ZXI Time cost: 56ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 28ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\7.png ZXI Time cost: 73ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 30ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\8.png ZXI Time cost: 55ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 27ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- F:\resources\blackbox\qrcode-1\9.png ZXI Time cost: 55ms ZXI Type: QR_CODE, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ZBA Time cost: 27ms ZBA Type: QR-Code, value: MEBKM:URL:http\://en.wikipedia.org/wiki/Main_Page;; ------------------------------------------------------------------------------------- ZXI passed: 19 ZBA passed: 20
结果发现,ZBar的二维码解码速度居然比ZXing快很多!感兴趣的同学可以去测试下别的数据。
源码
https://github.com/Dynamsoft/Dynamsoft-Barcode-Reader/tree/master/samples/Java