android條碼掃描程序
源碼下載地址:
地址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="<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></pre>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); } @Override public 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); }
}</pre>
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() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { // isAutoFocus = true; camera.setOneShotPreviewCallback(previewCallback); } } }; previewCallback = new Camera.PreviewCallback() { @Override public 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 picture Bitmap 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 { @Override public void run() { if (camera != null) { camera.autoFocus(mAutoFocusCallBack); } } } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder arg0) { // TODO Auto-generated method stub initCamera(surfaceHolder); } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub if (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; }
}</pre>這里要記得在AndroidManifest.xml中寫權限:
<uses-permission android:name="android.permission.CAMERA" /><uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /></pre>最后是BitmapLuminanceSource類:<p>思路見參考鏈接</p>
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]; } } @Override public byte[] getMatrix() { return bitmapPixels; } @Override public 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 block e.printStackTrace(); } if(result == null) return "empty"; else return result.toString(); }
}</pre>來自:http://blog.csdn.net/miaoyunzexiaobao/article/details/42142553