android条码扫描程序

jopen 5年前

源码下载地址:

地址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

目标:完成一个条码扫描程序,能识别出一维码和二维码,并将解析出来的结果显示出来

 

效果图:扫描中-》扫描成功

       20141225091909223.jpg              扫描成功后: 20141225094734602.jpg

首先在布局上放置一个预览框,用于实时显示摄像头拍摄到的情况,并在其上绘制一条来回扫描的线条。之后在其下方放一个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);    }     @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);   }    }

 

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;   }    }
这里要记得在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];    }   }   @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();   }  }
来自:http://blog.csdn.net/miaoyunzexiaobao/article/details/42142553