標籤:zxing barcode camera surface view
源碼:
地址1:https://github.com/alivebao/BarCodeReader
地址2:http://download.csdn.net/detail/miaoyunzexiaobao/8297201
參考連結:
zxing入門:http://www.cnblogs.com/liuan/archive/2012/01/05/2312714.html
BitmapLuminanceSource類實現:http://blog.csdn.net/xyz_fly/article/details/8089558
目標:完成一個條碼掃描程式,能識別出一維碼和二維碼,並將解析出來的結果顯示出來
:掃描中-》掃描成功
掃描成功後:
首先在布局上放置一個預覽框,用於即時顯示網路攝影機拍攝到的情況,並在其上繪製一條來回掃描的線條。之後在其下方放一個imageView,用於顯示網路攝影機自動聚焦後擷取的圖片。
實現:該Activity的整體布局為方向vertical的線性布局。該線性布局內嵌著一個幀布局和另一個線性布局。幀布局中先在底層防止了一個SurfaceView,用於顯示網路攝影機預覽圖片,再在其上放置了一個自己實現的View類ScanLineView,該類繼承自View,主要功能為在SurfaceView上繪製一條來回掃描的紅色線條。下面的LinearLayout放置了一個ImageView,用於顯示聚焦後獲得的圖片(程式自動對該圖片進行解碼)
code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <FrameLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight=".3" > <SurfaceView android:id="@+id/preview_view" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <com.miao.barcodereader.ScanLineView android:id="@+id/capture_viewfinder_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/transparent" /> </FrameLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight=".7" android:orientation="vertical" > <ImageView android:id="@+id/imageView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/ic_launcher" /> </LinearLayout></LinearLayout>
ScanLineView類:
繼承自View類,重載其onDraw函數,在onDraw函數中間隔一段時間發送申請重繪螢幕的請求,drawLine函數的功能為每次被調用時繪製一條橫座標逐漸增加的紅線。這個類要是嫌麻煩的話也可以不寫,把上面布局檔案中的ScanLineView控制項刪掉就行了,對程式功能沒什麼影響。
code:
package com.miao.barcodereader;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.util.AttributeSet;import android.view.View;public class ScanLineView extends View{private static final long ANIMATION_DELAY = 10L;private Paint paint;private int xLinePos = 0;private int canvasWidth = 0;private int canvasHeight = 0;public ScanLineView(Context context, AttributeSet attrs) {super(context, attrs);paint = new Paint(Paint.ANTI_ALIAS_FLAG); }@Overridepublic void onDraw(Canvas canvas) {canvasWidth = canvas.getWidth();canvasHeight = canvas.getHeight();drawLine(canvas);postInvalidateDelayed(ANIMATION_DELAY, 0, 0, canvasWidth, canvasHeight);}private void drawLine(Canvas canvas) {int iLineBegin = canvasWidth / 5;int iLineEnd = canvasWidth * 4 / 5;int iFrameHigh = canvasHeight ;Rect frame = new Rect(iLineBegin, 0, canvasWidth, iFrameHigh);xLinePos += 10;if (xLinePos > iLineEnd)xLinePos = iLineBegin;paint.setColor(Color.RED);canvas.drawRect(xLinePos, 0, xLinePos + 1, iFrameHigh, paint);}}
CameraManage類:
負責將預覽圖顯示到SurfaceView中,並每隔一段時間自動聚焦,聚焦成功後將獲得的圖片顯示在ImageView控制項中,並對該圖片進行解析。若解析成功則將結果以對話方塊形式彈出。在該類的建構函式中,先擷取主視窗的activity、imageView控制項和SurfaceView控制項,然後進行一些其他參數的設定。
本類實現了SurfaceHolder.Callback的介面,因此要實現surfaceChanged、surfaceCreated、surfaceDestroyed三個函數。在surfaceCreated中調用initCamera函數,開啟網路攝影機並將其預覽顯示在SurfaceView上。
本類實現了一個定時器CameraTimerTask,其功能為在網路攝影機成功開啟的情況下,每間隔一段使網路攝影機自動聚焦,並在聚焦的同時調用自動聚焦回呼函數mAutoFocusCallBack。該函數是自己實現的,其功能為當聚焦成功時,調用預覽回呼函數previewCallback。這個也是自己實現的,其功能為將擷取的預覽圖片置於ImageView中,並將該圖片轉為Bitmap格式,傳送給類BitmapLuminanceSource(該類收到圖片後對圖片進行解析,並返回一個string類型變數)。若該類解析成功則會返回解析出的條碼內容,若解析失敗則返回“empty”。在previewCallback中,若BitmapLuminanceSource返回的string不是“empty”,則證明解析成功,於是將結果顯示出來。
code:
package com.miao.barcodereader;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.util.Timer;import java.util.TimerTask;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.ImageFormat;import android.graphics.Matrix;import android.graphics.Rect;import android.graphics.YuvImage;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.hardware.Camera;import android.util.Log;import android.view.Display;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.WindowManager;import android.widget.ImageView;import android.widget.Toast;public class CameraManage implements SurfaceHolder.Callback {private SurfaceHolder surfaceHolder;private Camera camera;private Activity activity;SurfaceView surfaceView;private ImageView imageView;private Timer mTimer;private TimerTask mTimerTask;private Camera.AutoFocusCallback mAutoFocusCallBack;private Camera.PreviewCallback previewCallback;CameraManage(Activity ac, ImageView iv, SurfaceView sv) {activity = ac;imageView = iv;surfaceView = sv;surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(this);surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);AutoFocusSet();mTimer = new Timer();mTimerTask = new CameraTimerTask();mTimer.schedule(mTimerTask, 0, 500);}public void AutoFocusSet() {mAutoFocusCallBack = new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {if (success) {// isAutoFocus = true;camera.setOneShotPreviewCallback(previewCallback);}}};previewCallback = new Camera.PreviewCallback() {@Overridepublic void onPreviewFrame(byte[] data, Camera arg1) {if (data != null) {Camera.Parameters parameters = camera.getParameters();int imageFormat = parameters.getPreviewFormat();Log.i("map", "Image Format: " + imageFormat);Log.i("CameraPreviewCallback", "data length:" + data.length);if (imageFormat == ImageFormat.NV21) {// get full pictureBitmap image = null;int w = parameters.getPreviewSize().width;int h = parameters.getPreviewSize().height;Rect rect = new Rect(0, 0, w, h);YuvImage img = new YuvImage(data, ImageFormat.NV21, w,h, null);ByteArrayOutputStream baos = new ByteArrayOutputStream();if (img.compressToJpeg(rect, 100, baos)) {image = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size());image = adjustPhotoRotation(image, 90);imageView.setImageBitmap(image);Drawable d = imageView.getDrawable();BitmapDrawable bd = (BitmapDrawable) d;Bitmap bm = bd.getBitmap();String str = BitmapLuminanceSource.getResult(bm);if (!str.equals("empty"))Toast.makeText(activity.getApplication(), str,Toast.LENGTH_SHORT).show();}}}}};}class CameraTimerTask extends TimerTask {@Overridepublic void run() {if (camera != null) {camera.autoFocus(mAutoFocusCallBack);}}}@Overridepublic void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {// TODO Auto-generated method stub}@Overridepublic void surfaceCreated(SurfaceHolder arg0) {// TODO Auto-generated method stubinitCamera(surfaceHolder);}@Overridepublic void surfaceDestroyed(SurfaceHolder arg0) {// TODO Auto-generated method stubif (camera != null) {camera.stopPreview();camera.release();camera = null;}previewCallback = null;mAutoFocusCallBack = null;}public void initCamera(SurfaceHolder surfaceHolder) {camera = Camera.open();if (camera == null) {return;}Camera.Parameters parameters = camera.getParameters();WindowManager wm = (WindowManager) (activity.getSystemService(Context.WINDOW_SERVICE));Display display = wm.getDefaultDisplay(); parameters.setPreviewSize(display.getWidth(), display.getHeight());camera.setParameters(parameters);try {camera.setPreviewDisplay(surfaceHolder);} catch (IOException e) {System.out.println(e.getMessage());}camera.setDisplayOrientation(90);camera.startPreview();}public Bitmap adjustPhotoRotation(Bitmap bm, final int orientationDegree) {Matrix m = new Matrix();m.setRotate(orientationDegree, (float) bm.getWidth() / 2,(float) bm.getHeight() / 2);try {Bitmap bm1 = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),bm.getHeight(), m, true);return bm1;} catch (OutOfMemoryError ex) {}return null;}}這裡要記得在AndroidManifest.xml中寫入權限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
最後是BitmapLuminanceSource類:
思路見參考連結
code:
package com.miao.barcodereader;import java.util.HashMap;import java.util.Map;import android.graphics.Bitmap;import com.google.zxing.Binarizer;import com.google.zxing.BinaryBitmap;import com.google.zxing.EncodeHintType;import com.google.zxing.LuminanceSource;import com.google.zxing.MultiFormatReader;import com.google.zxing.NotFoundException;import com.google.zxing.Result;import com.google.zxing.common.HybridBinarizer;public class BitmapLuminanceSource extends LuminanceSource {private byte bitmapPixels[];protected BitmapLuminanceSource(Bitmap bitmap) {super(bitmap.getWidth(), bitmap.getHeight());int[] data = new int[bitmap.getWidth() * bitmap.getHeight()];this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()];bitmap.getPixels(data, 0, getWidth(), 0, 0, getWidth(), getHeight());for (int i = 0; i < data.length; i++) {this.bitmapPixels[i] = (byte) data[i];}}@Overridepublic byte[] getMatrix() {return bitmapPixels;}@Overridepublic byte[] getRow(int y, byte[] row) {System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth());return row;}static public String getResult(Bitmap bitmap){MultiFormatReader formatReader = new MultiFormatReader();LuminanceSource source = new BitmapLuminanceSource(bitmap);Binarizer binarizer = new HybridBinarizer(source);BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);Map hints = new HashMap();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");Result result = null;try {result = formatReader.decode(binaryBitmap, hints);} catch (NotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}if(result == null)return "empty";elsereturn result.toString();}}
android條碼掃描程式