• Android开发学习之基于相机扫描二维码、条形码等


    蛰伏半月有余,一直在准备期末考试,期间抽空研究了一些Android的源代码,现在我就把在这其中的一些收获分享给大家。

    今天想分享给大家的是二维码扫描。说起二维码,大家一定不会陌生,尤其是微信火了以后,在我们的生活中几乎随处都可以看到二维码的影

    子。相关科技媒体甚至把二维码当成是未来移动互联网的入口,因此研究二维码的相关技术就显得意义非凡。目前在移动开发领域,使用最为广泛的二

    维码库有两个,分别是ZXing和ZBar,其中ZXing在Android开发中较为常见,而ZBar则在IOS开发中较为常见,更重要的一点是,这两个库都是开源

    的,因此我们可以从源代码中获得很多有用的东西。关于ZXing,网上有很多相关的博文,我今天不想多说,我今天想说的是ZBar,你可能会说,ZBar

    不是用在IOS中,怎么今天要说ZBar呢?其实我是从这两个库使用的难易程度来选择的,ZXing功能强大,但是使用起来比较繁琐,网上有很多简化的

    教程,大家可以自行前去研究。相比较而言,ZBar则比较简单,使用起来容易上手,因此我们今天选择了ZBar作为我们的库来使用。

    一、准备工作

    下载ZBar的SDK:由于ZBar的项目托管在sourceforge,所以在这里给出下载地址:http://download.csdn.net/detail/qinyuanpei/6794713

    二、导入项目

    下载完成后,我们直接解压,可以看到下面的目录结构

    打开android文件夹,我们可以找到一个Example的文件夹,这是官方给出的示例代码,我们下面的所有工作都是基于这个示例程序而来。我们

    自行创建一个Android项目,并将这两个文件拷贝到我们的项目中,同时引入ZBar相关的库文件。

    三、建立布局

    首先建立主界面,即扫描二维码的界面,界面布局代码如下:

    <!--?xml version="1.0" encoding="utf-8"?-->
    <linearlayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">
      <relativelayout android:layout_height="40dp" android:layout_width="match_parent" android:background="@drawable/title_bg">
            <textview android:layout_height="wrap_content" android:layout_width="wrap_content" android:textsize="18sp" android:textcolor="#ffffff" android:text="@string/Scan" android:layout_centervertical="true" android:layout_centerhorizontal="true">
            <button android:id="@+id/BtnAbout" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="@string/BtnAbout" android:layout_alignparenttop="true" android:layout_alignparentright="true">
         
      <frameLayout
        android:id="@+id/cameraPreview"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"/>
     
    </button></textview></relativelayout></linearlayout>
    View Code

    实现的布局效果如下图所示:

    接下里,我们在来设计一个用于显示结果的界面,界面布局代码如下:

    <!--?xml version="1.0" encoding="utf-8"?-->
    <linearlayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" android:background="#ffffff">
        <relativelayout android:layout_height="40dp" android:layout_width="match_parent" android:background="@drawable/title_bg">
            <textview android:layout_height="wrap_content" android:layout_width="wrap_content" android:textsize="18sp" android:textcolor="#ffffff" android:text="@string/Result" android:layout_centervertical="true" android:layout_centerhorizontal="true">
            <button android:id="@+id/BtnBack" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="@string/BtnBack" android:layout_alignparenttop="true" android:layout_alignparentleft="true">
         
        <textview android:id="@+id/TextResult" android:layout_height="wrap_content" android:layout_width="match_parent" android:textcolor="#000000" android:textisselectable="true" android:layout_margin="8dp">
    </textview></button></textview></relativelayout></linearlayout>
    View Code

    实现的界面效果如图所示:

    四、编写代码

    首先我们来写一个用于扫描的相机预览视图CameraPreview,此文件由ZBar的SDK提供,这里我做了下简单的修改

    package com.Android.ZBar4Android;
     
    import java.io.IOException;
    import android.util.Log;
     
    import android.view.SurfaceView;
    import android.view.SurfaceHolder;
     
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.hardware.Camera;
    import android.hardware.Camera.Parameters;
    import android.hardware.Camera.PreviewCallback;
    import android.hardware.Camera.AutoFocusCallback;
     
    //此类由ZBar项目的SDK提供,我做了下修改
    @SuppressLint("ViewConstructor")
    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback 
    {
         
        private SurfaceHolder mHolder;
        private Camera mCamera;
        private PreviewCallback mPreviewCallBack;
        private AutoFocusCallback mAutoFocusCallBack;
     
        public CameraPreview(Context context, Camera camera,
                             PreviewCallback previewCb,
                             AutoFocusCallback autoFocusCb) {
            super(context);
            mCamera = camera;
            mPreviewCallBack = previewCb;
            mAutoFocusCallBack = autoFocusCb;
     
            /* 
             * 自动聚焦
             * 要求API版本>9
             */
            Camera.Parameters parameters = camera.getParameters();
            for (String f : parameters.getSupportedFocusModes()) {
                if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
                    parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                    mAutoFocusCallBack = null;
                    break;
                }
            }
     
     
            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            mHolder = getHolder();
            mHolder.addCallback(this);
     
            // deprecated setting, but required on Android versions prior to 3.0
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
     
     
        public void surfaceCreated(SurfaceHolder holder) {
            // The Surface has been created, now tell the camera where to draw the preview.
            try {
                mCamera.setPreviewDisplay(holder);
            } catch (IOException e) {
                Log.d("DBG", "Error setting camera preview: " + e.getMessage());
            }
        }
     
        public void surfaceDestroyed(SurfaceHolder holder) {
            // Camera preview released in activity
        }
     
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            /*
             * If your preview can change or rotate, take care of those events here.
             * Make sure to stop the preview before resizing or reformatting it.
             */
            if (mHolder.getSurface() == null){
              // preview surface does not exist
              return;
            }
     
            // stop preview before making changes
            try {
                mCamera.stopPreview();
            } catch (Exception e){
              // ignore: tried to stop a non-existent preview
            }
     
            try {
                // Hard code camera surface rotation 90 degs to match Activity view in portrait
                mCamera.setDisplayOrientation(90);
     
                mCamera.setPreviewDisplay(mHolder);
                mCamera.setPreviewCallback(mPreviewCallBack);
                mCamera.startPreview();
                mCamera.autoFocus(mAutoFocusCallBack);
            } catch (Exception e){
                Log.d("DBG", "Error starting camera preview: " + e.getMessage());
            }
        }
         
        /*
         * 绘制校准框
         * 修改:秦元培
         * 时间:2013年11月22日
         * 
         */
        @Override
        protected void onDraw(Canvas mCanvas) 
        {
           //这里不会写了?
        }
    }
    View Code

    接下来,我们来编写主界面的逻辑代码,在这里我们需要搞清楚的几个问题有:

    1、相机的获取及相机的交互处理

    2、二维码图片的获取

    3、二维码图片的解析

    对于第一个问题,需要我们深入地了解相机的工作原理,即我们需要了解Camera类。

    获取相机的代码如下:

    //获取照相机的方法
        public static Camera getCameraInstance()
        {
            Camera mCamera = null;
            try
            {
                mCamera = Camera.open();
                //没有后置摄像头,尝试打开前置摄像头*******************
                if (mCamera == null)
                {
                    Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
                    int cameraCount = Camera.getNumberOfCameras(); 
                    for (int camIdx = 0; camIdx < cameraCount; camIdx++)
                    {
                        Camera.getCameraInfo(camIdx, mCameraInfo); 
                        if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
                        {
                            mCamera = Camera.open(camIdx);                        
                        }
                }
            }
        }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            return mCamera;
        }
    View Code

    释放照相机的方法

    //释放照相机
        private void releaseCamera()
        {
            if (mCamera != null)
            {
                IsPreview = false;
                mCamera.setPreviewCallback(null);
                mCamera.release();
                mCamera = null;
            }
        }
    View Code

    相机反馈的方法,即扫描到二维码后的处理

    PreviewCallback previewCb = new PreviewCallback()
        {
            public void onPreviewFrame(byte[] data, Camera camera)
            {
                Camera.Parameters parameters = camera.getParameters();
                //获取扫描图片的大小
                Size mSize = parameters.getPreviewSize();
                //构造存储图片的Image
                Image mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的
                //设置Image的数据资源
                mResult.setData(data);
                //获取扫描结果的代码
                int mResultCode = mScanner.scanImage(mResult);
                //如果代码不为0,表示扫描成功
                if (mResultCode != 0)
                {
                    //停止扫描
                    IsPreview = false;
                    mCamera.setPreviewCallback(null);
                    mCamera.stopPreview();
                    //开始解析扫描图片
                    SymbolSet Syms = mScanner.getResults();
                    for (Symbol mSym : Syms)
                    {
                        //mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别
                        if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || 
                            mSym.getType() == Symbol.CODABAR || mSym.getType() == Symbol.ISBN10 ||
                            mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR ||
                            mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25)
                                  
                        {
                            //添加震动效果,提示用户扫描完成
                            Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);
                            mVibrator.vibrate(400);
                            Intent intent=new Intent(MainActivity.this,ResultActivity.class);
                            intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+"
    "+ mSym.getData());
                            //这里需要注意的是,getData方法才是最终返回识别结果的方法
                            //但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义
                            //例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割
                            //效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理
                            startActivity(intent);
                            IsScanned = true;
                        }
                        else
                        {
                            //否则继续扫描
                            IsScanned = false;
                            mCamera.setPreviewCallback(previewCb);
                            mCamera.startPreview();
                            IsPreview = true;
                            mCamera.autoFocus(autoFocusCB);
                        }
                    }
                }
            }
        };
    View Code

    对于第二个问题,从上面的代码中我们可以看出,Image类用于获取二维码图片,ImageScanner类用于对图片的初步解析,而图片的最终解析是在SymbolSet类和

    Symbol中去实现的,由此,第三个问题得以解答。下面给出完整代码:

    /*
     * ZBar4Android
     * 作者:秦元培
     * 时间:2013年12月21日
     * 需要解决的问题有:
     * 1、返回内容的正则解析
     * 2、如果锁屏后打开程序会报错
     * 3、没有校正框,画不出来啊,郁闷
     * 4、可能会与其它相机应用冲突,如微信
     * 5、条形码还是读不出来
     */
    package com.Android.ZBar4Android;
     
    import com.Android.ZBar4Android.CameraPreview;
    import com.Android.ZBar4Android.R;
     
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.pm.ActivityInfo;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Vibrator;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup.LayoutParams;
    import android.view.Window;
    import android.view.View.OnClickListener;
    import android.widget.FrameLayout;
    import android.widget.Button;
    import android.widget.PopupWindow;
    import android.hardware.Camera;
    import android.hardware.Camera.PreviewCallback;
    import android.hardware.Camera.AutoFocusCallback;
    import android.hardware.Camera.Size;
      
    import net.sourceforge.zbar.ImageScanner;
    import net.sourceforge.zbar.Image;
    import net.sourceforge.zbar.Symbol;
    import net.sourceforge.zbar.SymbolSet;
    import net.sourceforge.zbar.Config;
     
    public class MainActivity extends Activity
    {
        //关于按钮
        private Button BtnAbout;
        //相机
        private Camera mCamera;
        //预览视图
        private CameraPreview mPreview;
        //自动聚焦
        private Handler mAutoFocusHandler;
        //图片扫描器
        private ImageScanner mScanner;
        //弹出窗口
        private PopupWindow mPopupWindow;
        //是否扫描完毕
        private boolean IsScanned = false;
        //是否处于预览状态
        private boolean IsPreview = true;
        //是否显示弹出层
        private boolean IsShowPopup=false;
     
        //加载iconvlib
        static
        {
            System.loadLibrary("iconv");
        }
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            //去除标题栏
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.layout_main);
            //设置屏幕方向为竖屏
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            //自动聚焦线程
            mAutoFocusHandler = new Handler();
            //获取相机实例
            mCamera = getCameraInstance();
            if(mCamera == null)
            {
                //在这里写下获取相机失败的代码
                AlertDialog.Builder mBuilder=new AlertDialog.Builder(this);
                mBuilder.setTitle("ZBar4Android");
                mBuilder.setMessage("ZBar4Android获取相机失败,请重试!");
                mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener()
                {
     
                    @Override
                    public void onClick(DialogInterface mDialogInterface, int mIndex) 
                    {
                        MainActivity.this.finish();
                    }
                });
                AlertDialog mDialog=mBuilder.create();
                mDialog.show();
            }
            //实例化Scanner
            mScanner = new ImageScanner();
            mScanner.setConfig(0, Config.X_DENSITY, 3);
            mScanner.setConfig(0, Config.Y_DENSITY, 3);
           //设置相机预览视图
            mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
            FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
            preview.addView(mPreview);
            if (IsScanned)
              {
                 IsScanned = false;
                 mCamera.setPreviewCallback(previewCb);
                 mCamera.startPreview();
                 IsPreview = true;
                 mCamera.autoFocus(autoFocusCB);
              }
            //获取BtnAbout,显示程序信息
            BtnAbout=(Button)findViewById(R.id.BtnAbout);
            BtnAbout.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    //如果弹出层已打开,销毁弹出层
                    if(IsShowPopup)
                    {
                        mPopupWindow.dismiss();
                        IsShowPopup=false;
                    }
                    else
                    {
                        //否则显示弹出层
                        mPopupWindow=new PopupWindow();
                        LayoutInflater mInflater=LayoutInflater.from(getApplicationContext());
                        View view=mInflater.inflate(R.layout.layout_about, null);
                        mPopupWindow.setContentView(view);
                        mPopupWindow.setWidth(LayoutParams.WRAP_CONTENT);
                        mPopupWindow.setHeight(LayoutParams.WRAP_CONTENT);
                        mPopupWindow.showAtLocation(mPreview, 0, 100, 100);
                        IsShowPopup=true;
                    }
                } 
            });
        }
        //实现Pause方法
        public void onPause()
        {
            super.onPause();
            releaseCamera();
        }
        //获取照相机的方法
        public static Camera getCameraInstance()
        {
            Camera mCamera = null;
            try
            {
                mCamera = Camera.open();
                //没有后置摄像头,尝试打开前置摄像头*******************
                if (mCamera == null)
                {
                    Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
                    int cameraCount = Camera.getNumberOfCameras(); 
                    for (int camIdx = 0; camIdx < cameraCount; camIdx++)
                    {
                        Camera.getCameraInfo(camIdx, mCameraInfo); 
                        if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
                        {
                            mCamera = Camera.open(camIdx);                        
                        }
                }
            }
        }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            return mCamera;
        }
     
        //释放照相机
        private void releaseCamera()
        {
            if (mCamera != null)
            {
                IsPreview = false;
                mCamera.setPreviewCallback(null);
                mCamera.release();
                mCamera = null;
            }
        }
     
        private Runnable doAutoFocus = new Runnable()
        {
            public void run()
            {
                if (IsPreview)
                    mCamera.autoFocus(autoFocusCB);
            }
        };
     
        PreviewCallback previewCb = new PreviewCallback()
        {
            public void onPreviewFrame(byte[] data, Camera camera)
            {
                Camera.Parameters parameters = camera.getParameters();
                //获取扫描图片的大小
                Size mSize = parameters.getPreviewSize();
                //构造存储图片的Image
                Image mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的
                //设置Image的数据资源
                mResult.setData(data);
                //获取扫描结果的代码
                int mResultCode = mScanner.scanImage(mResult);
                //如果代码不为0,表示扫描成功
                if (mResultCode != 0)
                {
                    //停止扫描
                    IsPreview = false;
                    mCamera.setPreviewCallback(null);
                    mCamera.stopPreview();
                    //开始解析扫描图片
                    SymbolSet Syms = mScanner.getResults();
                    for (Symbol mSym : Syms)
                    {
                        //mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别
                        if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || 
                            mSym.getType() == Symbol.CODABAR || mSym.getType() == Symbol.ISBN10 ||
                            mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR ||
                            mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25)
                                  
                        {
                            //添加震动效果,提示用户扫描完成
                            Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);
                            mVibrator.vibrate(400);
                            Intent intent=new Intent(MainActivity.this,ResultActivity.class);
                            intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+"
    "+ mSym.getData());
                            //这里需要注意的是,getData方法才是最终返回识别结果的方法
                            //但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义
                            //例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割
                            //效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理
                            startActivity(intent);
                            IsScanned = true;
                        }
                        else
                        {
                            //否则继续扫描
                            IsScanned = false;
                            mCamera.setPreviewCallback(previewCb);
                            mCamera.startPreview();
                            IsPreview = true;
                            mCamera.autoFocus(autoFocusCB);
                        }
                    }
                }
            }
        };
     
        //用于刷新自动聚焦的方法
        AutoFocusCallback autoFocusCB = new AutoFocusCallback()
        {
            public void onAutoFocus(boolean success, Camera camera)
            {
                mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
            }
        };
         
        //根据返回的代码值来返回相应的格式化数据
        public String GetResultByCode(int CodeType)
        {
            String mResult="";
            switch(CodeType)
            {
              //条形码
              case Symbol.CODABAR:
                  mResult="条形码";
                  break;
              //128编码格式二维码)
              case Symbol.CODE128:
                  mResult="二维码";
                  break;
              //QR码二维码
              case Symbol.QRCODE:
                  mResult="二维码";
                  break;
              //ISBN10图书查询
              case Symbol.ISBN10:
                  mResult="图书ISBN号";
                  break;
              //ISBN13图书查询
              case Symbol.ISBN13:
                  mResult="图书ISBN号";
                  break;
            }
            return mResult;
        }
      
         
    }
    
    /*
     * ZBar4Android
     * 作者:秦元培
     * 时间:2013年12月21日
     * 需要解决的问题有:
     * 1、返回内容的正则解析
     * 2、如果锁屏后打开程序会报错
     * 3、没有校正框,画不出来啊,郁闷
     * 4、可能会与其它相机应用冲突,如微信
     * 5、条形码还是读不出来
     */
    package com.Android.ZBar4Android;
     
    import com.Android.ZBar4Android.CameraPreview;
    import com.Android.ZBar4Android.R;
     
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.pm.ActivityInfo;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Vibrator;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup.LayoutParams;
    import android.view.Window;
    import android.view.View.OnClickListener;
    import android.widget.FrameLayout;
    import android.widget.Button;
    import android.widget.PopupWindow;
    import android.hardware.Camera;
    import android.hardware.Camera.PreviewCallback;
    import android.hardware.Camera.AutoFocusCallback;
    import android.hardware.Camera.Size;
      
    import net.sourceforge.zbar.ImageScanner;
    import net.sourceforge.zbar.Image;
    import net.sourceforge.zbar.Symbol;
    import net.sourceforge.zbar.SymbolSet;
    import net.sourceforge.zbar.Config;
     
    public class MainActivity extends Activity
    {
        //关于按钮
        private Button BtnAbout;
        //相机
        private Camera mCamera;
        //预览视图
        private CameraPreview mPreview;
        //自动聚焦
        private Handler mAutoFocusHandler;
        //图片扫描器
        private ImageScanner mScanner;
        //弹出窗口
        private PopupWindow mPopupWindow;
        //是否扫描完毕
        private boolean IsScanned = false;
        //是否处于预览状态
        private boolean IsPreview = true;
        //是否显示弹出层
        private boolean IsShowPopup=false;
     
        //加载iconvlib
        static
        {
            System.loadLibrary("iconv");
        }
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            //去除标题栏
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.layout_main);
            //设置屏幕方向为竖屏
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            //自动聚焦线程
            mAutoFocusHandler = new Handler();
            //获取相机实例
            mCamera = getCameraInstance();
            if(mCamera == null)
            {
                //在这里写下获取相机失败的代码
                AlertDialog.Builder mBuilder=new AlertDialog.Builder(this);
                mBuilder.setTitle("ZBar4Android");
                mBuilder.setMessage("ZBar4Android获取相机失败,请重试!");
                mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener()
                {
     
                    @Override
                    public void onClick(DialogInterface mDialogInterface, int mIndex) 
                    {
                        MainActivity.this.finish();
                    }
                });
                AlertDialog mDialog=mBuilder.create();
                mDialog.show();
            }
            //实例化Scanner
            mScanner = new ImageScanner();
            mScanner.setConfig(0, Config.X_DENSITY, 3);
            mScanner.setConfig(0, Config.Y_DENSITY, 3);
           //设置相机预览视图
            mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
            FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
            preview.addView(mPreview);
            if (IsScanned)
              {
                 IsScanned = false;
                 mCamera.setPreviewCallback(previewCb);
                 mCamera.startPreview();
                 IsPreview = true;
                 mCamera.autoFocus(autoFocusCB);
              }
            //获取BtnAbout,显示程序信息
            BtnAbout=(Button)findViewById(R.id.BtnAbout);
            BtnAbout.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    //如果弹出层已打开,销毁弹出层
                    if(IsShowPopup)
                    {
                        mPopupWindow.dismiss();
                        IsShowPopup=false;
                    }
                    else
                    {
                        //否则显示弹出层
                        mPopupWindow=new PopupWindow();
                        LayoutInflater mInflater=LayoutInflater.from(getApplicationContext());
                        View view=mInflater.inflate(R.layout.layout_about, null);
                        mPopupWindow.setContentView(view);
                        mPopupWindow.setWidth(LayoutParams.WRAP_CONTENT);
                        mPopupWindow.setHeight(LayoutParams.WRAP_CONTENT);
                        mPopupWindow.showAtLocation(mPreview, 0, 100, 100);
                        IsShowPopup=true;
                    }
                } 
            });
        }
        //实现Pause方法
        public void onPause()
        {
            super.onPause();
            releaseCamera();
        }
        //获取照相机的方法
        public static Camera getCameraInstance()
        {
            Camera mCamera = null;
            try
            {
                mCamera = Camera.open();
                //没有后置摄像头,尝试打开前置摄像头*******************
                if (mCamera == null)
                {
                    Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
                    int cameraCount = Camera.getNumberOfCameras(); 
                    for (int camIdx = 0; camIdx < cameraCount; camIdx++)
                    {
                        Camera.getCameraInfo(camIdx, mCameraInfo); 
                        if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
                        {
                            mCamera = Camera.open(camIdx);                        
                        }
                }
            }
        }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            return mCamera;
        }
     
        //释放照相机
        private void releaseCamera()
        {
            if (mCamera != null)
            {
                IsPreview = false;
                mCamera.setPreviewCallback(null);
                mCamera.release();
                mCamera = null;
            }
        }
     
        private Runnable doAutoFocus = new Runnable()
        {
            public void run()
            {
                if (IsPreview)
                    mCamera.autoFocus(autoFocusCB);
            }
        };
     
        PreviewCallback previewCb = new PreviewCallback()
        {
            public void onPreviewFrame(byte[] data, Camera camera)
            {
                Camera.Parameters parameters = camera.getParameters();
                //获取扫描图片的大小
                Size mSize = parameters.getPreviewSize();
                //构造存储图片的Image
                Image mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的
                //设置Image的数据资源
                mResult.setData(data);
                //获取扫描结果的代码
                int mResultCode = mScanner.scanImage(mResult);
                //如果代码不为0,表示扫描成功
                if (mResultCode != 0)
                {
                    //停止扫描
                    IsPreview = false;
                    mCamera.setPreviewCallback(null);
                    mCamera.stopPreview();
                    //开始解析扫描图片
                    SymbolSet Syms = mScanner.getResults();
                    for (Symbol mSym : Syms)
                    {
                        //mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别
                        if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || 
                            mSym.getType() == Symbol.CODABAR || mSym.getType() == Symbol.ISBN10 ||
                            mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR ||
                            mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25)
                                  
                        {
                            //添加震动效果,提示用户扫描完成
                            Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);
                            mVibrator.vibrate(400);
                            Intent intent=new Intent(MainActivity.this,ResultActivity.class);
                            intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+"
    "+ mSym.getData());
                            //这里需要注意的是,getData方法才是最终返回识别结果的方法
                            //但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义
                            //例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割
                            //效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理
                            startActivity(intent);
                            IsScanned = true;
                        }
                        else
                        {
                            //否则继续扫描
                            IsScanned = false;
                            mCamera.setPreviewCallback(previewCb);
                            mCamera.startPreview();
                            IsPreview = true;
                            mCamera.autoFocus(autoFocusCB);
                        }
                    }
                }
            }
        };
     
        //用于刷新自动聚焦的方法
        AutoFocusCallback autoFocusCB = new AutoFocusCallback()
        {
            public void onAutoFocus(boolean success, Camera camera)
            {
                mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
            }
        };
         
        //根据返回的代码值来返回相应的格式化数据
        public String GetResultByCode(int CodeType)
        {
            String mResult="";
            switch(CodeType)
            {
              //条形码
              case Symbol.CODABAR:
                  mResult="条形码";
                  break;
              //128编码格式二维码)
              case Symbol.CODE128:
                  mResult="二维码";
                  break;
              //QR码二维码
              case Symbol.QRCODE:
                  mResult="二维码";
                  break;
              //ISBN10图书查询
              case Symbol.ISBN10:
                  mResult="图书ISBN号";
                  break;
              //ISBN13图书查询
              case Symbol.ISBN13:
                  mResult="图书ISBN号";
                  break;
            }
            return mResult;
        }
      
         
    }
    View Code

    对于显示扫描结果的界面,代码比较简单

    /*
     * 返回扫描结果
     * 作者:秦元培
     * 时间:2013年12月21日
     * 总结:这里有一个问题,就是在这个界面上按下返回键的时候程序会立即报错,试着重写过相关的方法都解决不了问题
     * 谁要是知道这个问题怎么解决,记得给我说一声啊
     */
    package com.Android.ZBar4Android;
     
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.Window;
    import android.widget.Button;
    import android.widget.TextView;
     
    public class ResultActivity extends Activity 
    {
     
        private TextView tv;
        private Button BtnBack;
        @Override
        protected void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.layout_result);
            //获取扫描结果
            Intent intent=getIntent();
            Bundle mData=intent.getExtras();
            CharSequence mResult=mData.getCharSequence("ScanResult");
            StringHelper mHelper=new StringHelper(mResult.toString());
            mResult=mHelper.SplitFormDict();
            tv=(TextView)findViewById(R.id.TextResult);
            tv.setText(mResult);
            //返回扫描界面
            BtnBack=(Button)findViewById(R.id.BtnBack);
            BtnBack.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View arg0) 
                {
                    Intent intent=new Intent(ResultActivity.this,MainActivity.class);
                    startActivity(intent);
                }
                 
            });
        }
         
        @Override
        protected void onPause() 
        {
            super.onPause();
        }
         
    }
    View Code

    五、总结

    经过测试,可以快速地对二维码进行识别,并显示扫描结果。目前尚存在的问题有:

    1、官方的文档说它是支持条形码、ISBN、二维码等多种形式的编码的,并且在程序代码中亦有所体现,但是实际测试中,发现二维码可以扫,其余的无法扫描

    2、锁屏后再次打开程序会报错

    3、与微信等类似的需要相机功能的软件冲突

    4、校准框死活画不出来

    5、在扫描结果界面下按下返回键,程序报错,无法拦截

    欢迎大家积极寻找解决问题的方法,再次谢谢大家!

    源代码下载

  • 相关阅读:
    iOS的几种动画使用
    iOS工程师必备技能
    网络数据的下载(NSUrlconnection异步下载和NSstring同步下载)和UI界面数据的刷新(都是抛弃第三方库的一些本质)
    GCD定时器
    iOS开发的小技巧
    站在巨人的肩膀上
    跳转系统设置相关界面的方法
    微信分享
    网站 、内容
    加水印
  • 原文地址:https://www.cnblogs.com/a354823200/p/3939238.html
Copyright © 2020-2023  润新知