Edited by mythouhtml
原創博文,轉載請標明出處:http://www.cnblogs.com/mythou/p/3280023.htmljava
已測試 -- 絕對靠譜android
今天講一下目前移動領域很經常使用的技術——二維碼。如今大街小巷、各大網站都有二維碼的蹤影,不論是IOS、Android、WP都有相關支持的軟件。以前我就想了解二維碼是如何工做,最近由於工做須要使用相關技術,因此作了初步瞭解。今天主要是講解如何使用ZXing庫,生成和識別二維碼。這篇文章實用性爲主,理論性不會講解太多,有興趣能夠本身查看源碼。web
一、ZXing庫介紹算法
這裏簡單介紹一下ZXing庫。ZXing是一個開放源碼的,用Java實現的多種格式的1D/2D條碼圖像處理庫,它包含了聯繫到其餘語言的端口。Zxing能夠實現使用手機的內置的攝像頭完成條形碼的掃描及解碼。該項目可實現的條形碼編碼和解碼。目前支持如下格式:UPC-A,UPC-E、EAN-8,EAN-1三、39碼、93碼。ZXing是個很經典的條碼/二維碼識別的開源類庫,之前在功能機上,就有開發者使用J2ME運用ZXing了,不過要支持JSR-234規範(自動對焦)的手機才能發揮其威力。瀏覽器
下面是ZXing的demo運行,我這裏建立了一個二維碼,內容是我博客的網址,大夥能夠用微信的掃一掃功能,試一下。就能夠直接打開我博客。微信
二、ZXing庫主要類ide
下面給你們介紹一下,ZXing庫裏面主要的類以及這些類的做用:函數
CaptureActivity。這個是啓動Activity 也就是掃描器。測試
CaptureActivityHandler 解碼處理類,負責調用另外的線程進行解碼。
DecodeThread 解碼的線程。
com.google.zxing.client.android.camera 包,攝像頭控制包。
ViewfinderView 自定義的View,就是咱們看見的拍攝時中間的框框了。
三、使用ZXing生成二維碼
下面針對二維碼生成和解析作個簡單介紹,至於詳細的使用方法,建議你們仍是本身看看源碼,使用起來很簡單,不過這個開源項目的代碼,值得好好看看。首先給出二維碼生成的方法:
//Edited by mythou //http://www.cnblogs.com/mythou/ //要轉換的地址或字符串,能夠是中文 public void createQRImage(String url) { try { //判斷URL合法性 if (url == null || "".equals(url) || url.length() < 1) { return; } Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>(); hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //圖像數據轉換,使用了矩陣轉換 BitMatrix bitMatrix = new QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints); int[] pixels = new int[QR_WIDTH * QR_HEIGHT]; //下面這裏按照二維碼的算法,逐個生成二維碼的圖片, //兩個for循環是圖片橫列掃描的結果 for (int y = 0; y < QR_HEIGHT; y++) { for (int x = 0; x < QR_WIDTH; x++) { if (bitMatrix.get(x, y)) { pixels[y * QR_WIDTH + x] = 0xff000000; } else { pixels[y * QR_WIDTH + x] = 0xffffffff; } } } //生成二維碼圖片的格式,使用ARGB_8888 Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT); //顯示到一個ImageView上面 sweepIV.setImageBitmap(bitmap); } catch (WriterException e) { e.printStackTrace(); } }
上面就是二維碼生成的方法接口,若是你只是使用者方法,很簡單,只要傳入一個URL便可,就像我截圖裏面同樣,傳入一個合法的網址便可。或者像如今一些移動APP的推廣,把APP下載地址轉爲二維碼,只要掃一下就能夠下載相應的APP。這個也是目前比較流行的APP的推廣方式。
上面代碼作的事情很少,主要是調用ZXing庫裏面QRCodeWriter().encode的方法對咱們傳進去的URL進行編碼,具體如何編碼,這個我這裏就不詳細說,有興趣能夠看ZXing的源碼。文章最後會給出ZXing的源碼和例子代碼。
四、掃描二維碼獲取信息
掃描獲取二維碼信息的工做稍微複雜一些,主要是須要編寫Camera的使用,這個跟咱們通常使用Camera同樣,須要使用Surfaceview做爲預覽,這一部我這裏就不說了,這個應該不是太複雜。對於使用過Camera作預覽的朋友,應該是挺簡單的事情。獲取二維碼數據的關鍵處理是在Camera的自動對焦回調函數哪裏,調用ZXing的解碼接口。
//Edited by mythou//http://www.cnblogs.com/mythou/ private void restartPreviewAndDecode() { if (state == State.SUCCESS) { state = State.PREVIEW; CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); CameraManager.get().requestAutoFocus(this, R.id.auto_focus); activity.drawViewfinder(); } }
這裏稍微多說一句,因爲解碼須要必定時間,因此ZXing的解碼調用,都是使用了Handler做爲線程通訊機制,解碼的工做都是放在獨立線程裏面使用的,若是你直接在主線程解碼,恐怕ANR問題是避免不了。
//Edited by mythou //http://www.cnblogs.com/mythou/ public void handleMessage(Message message) { switch (message.what) { case R.id.auto_focus: //Log.d(TAG, "Got auto-focus message"); // When one auto focus pass finishes, start another. This is the closest thing to // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do. if (state == State.PREVIEW) { CameraManager.get().requestAutoFocus(this, R.id.auto_focus); } break; case R.id.restart_preview: Log.d(TAG, "Got restart preview message"); restartPreviewAndDecode(); break; case R.id.decode_succeeded: //解碼成功,獲取到界面的結果和原來的二維碼數據 Log.d(TAG, "Got decode succeeded message"); state = State.SUCCESS; Bundle bundle = message.getData(); Bitmap barcode = bundle == null ? null : (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP); activity.handleDecode((Result) message.obj, barcode); break; case R.id.decode_failed: // We're decoding as fast as possible, so when one decode fails, start another. state = State.PREVIEW; CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); break; case R.id.return_scan_result: Log.d(TAG, "Got return scan result message"); activity.setResult(Activity.RESULT_OK, (Intent) message.obj); activity.finish(); break; case R.id.launch_product_query: Log.d(TAG, "Got product query message"); String url = (String) message.obj; Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); activity.startActivity(intent); break; } }
上面是解碼的線程處理不一樣狀態的時候須要注意的地方,咱們這裏只看獲取圖像成功的地方,成功獲取圖片解碼的實在DecodeThread裏面實現,DecodeThread裏面解碼成功後,會把數據序列化,而後保存到Bundle裏面,咱們能夠直接經過Bundle的序列化,獲取到圖片數據。同時會把解碼後的結果保存到MSG裏面,而後就能夠根據實際狀況進行處理,例如上面代碼,解碼成功後,會調用一個處理函數:
//Edited by mythou //http://www.cnblogs.com/mythou/ public void handleDecode(final Result obj, Bitmap barcode) { inactivityTimer.onActivity(); playBeepSoundAndVibrate(); AlertDialog.Builder dialog = new AlertDialog.Builder(this); if (barcode == null) { dialog.setIcon(null); } else { Drawable drawable = new BitmapDrawable(barcode); dialog.setIcon(drawable); } dialog.setTitle("掃描結果"); dialog.setMessage(obj.getText()); dialog.setNegativeButton("肯定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //用默認瀏覽器打開掃描獲得的地址 Intent intent = new Intent(); intent.setAction("android.intent.action.VIEW"); Uri content_url = Uri.parse(obj.getText()); intent.setData(content_url); startActivity(intent); finish(); } }); dialog.setPositiveButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); dialog.create().show(); }
上面就是整個二維碼的解碼流程,裏面由於涉及不少Camera的使用,因此你若是須要使用二維碼識別,須要注意一下你的程序須要申請下面的權限,通常的Camera使用以及Camera的自動對焦等。
//Edited by mythou//http://www.cnblogs.com/mythou/ <uses-permission android:name="android.permission.CAMERA"></uses-permission><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
ZXing開源項目Google Code地址:https://code.google.com/p/zxing/
ZXingDemo下載:ZXingDemo2013-8-25.rar