二维码、条形码扫描

由于项目中遇到扫描条形码

参考了下github的开源项目

https://github.com/bingoogolapple/BGAQRCode-Android

内部有两种实现

1.zxing 算法java实现
2.zbar 算法c实现
经过测试 发现zbar所扫描出的结果准备率相对高一些

针对zxing进行源码分析:

扫描界面是个relativelayout 内部由

   public abstract class QRCodeView extends RelativeLayout implements Camera.PreviewCallback, ProcessDataTask.Delegate 

初始化

    private void initView(Context context, AttributeSet attrs) {
    mPreview = new CameraPreview(getContext());//surfaceview 将camera //mCamera.setPreviewDisplay(getHolder());
    mScanBoxView = new ScanBoxView(getContext());
    mScanBoxView.initCustomAttrs(context, attrs);
    mPreview.setId(R.id.bgaqrcode_camera_preview);
    addView(mPreview);
    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(context, attrs);
    layoutParams.addRule(RelativeLayout.ALIGN_TOP, mPreview.getId());
    layoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, mPreview.getId());
    addView(mScanBoxView, layoutParams);
    mOrientation = BGAQRCodeUtil.getOrientation(context);
}

mPreview 是个surfaceview camera将摄像头的画面设置的这个surfaceview上mCamera.setPreviewDisplay(getHolder());

 public void showCameraPreview() {
    if (mCamera != null) {
        try {
            mPreviewing = true;
            mCamera.setPreviewDisplay(getHolder());

            mCameraConfigurationManager.setDesiredCameraParameters(mCamera);
            mCamera.startPreview();

            mCamera.autoFocus(autoFocusCB);//通过handle设置自动聚焦任务 定时聚焦
        } catch (Exception e) {
            Log.e(TAG, e.toString(), e);
        }
    }
}

通过camera设置摄像头照片回调监听

 /**
 * 延迟delay毫秒后开始识别
 *
 * @param delay
 */
public void startSpotDelay(int delay) {
    mSpotAble = true;

    startCamera();
    // 开始前先移除之前的任务
    mHandler.removeCallbacks(mOneShotPreviewCallbackTask);
    mHandler.postDelayed(mOneShotPreviewCallbackTask, delay);
} 


  private Runnable mOneShotPreviewCallbackTask = new Runnable() {
    @Override
    public void run() {
        if (mCamera != null && mSpotAble) {
            try {
                mCamera.setOneShotPreviewCallback(QRCodeView.this); //设置回调
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
};

//此处是camera回调  由于计算图片比较耗时 启动异步处理 
@Override
public void onPreviewFrame(final byte[] data, final Camera camera) {
    if (mSpotAble) {
        cancelProcessDataTask();
        Log.e("scan","onPreviewFrame");
        mProcessDataTask = new ProcessDataTask(camera, data, this, mOrientation) {
            @Override
            protected void onPostExecute(String result) {
                if (mSpotAble) {
                    if (mDelegate != null && !TextUtils.isEmpty(result)) {
                        try {
                            Log.e("scan","onScanQRCodeSuccess:"+result);
                            mDelegate.onScanQRCodeSuccess(result);
                        } catch (Exception e) {
                        }
                    } else {
                        try {
                            Log.e("scan","error:"+result);
                            camera.setOneShotPreviewCallback(QRCodeView.this);
                        } catch (Exception e) {
                        }
                    }
                }
            }
        }.perform();
    }
}
    //内部子线程处理过程 
   @Override
protected String doInBackground(Void... params) {
    Camera.Parameters parameters = mCamera.getParameters();
    Camera.Size size = parameters.getPreviewSize();
    int width = size.width;
    int height = size.height;

    byte[] data = mData;

    if (orientation == BGAQRCodeUtil.ORIENTATION_PORTRAIT) {
        data = new byte[mData.length];
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                data[x * height + height - y - 1] = mData[x + y * width];
            }
        }
        int tmp = width;
        width = height;
        height = tmp;
    }

    try {
        if (mDelegate == null) {
            return null;
        }
        return mDelegate.processData(data, width, height, false);
    } catch (Exception e1) {
        try {
            return mDelegate.processData(data, width, height, true);
        } catch (Exception e2) {
            return null;
        }
    }
}

public interface Delegate {
    String processData(byte[] data, int width, int height, boolean isRetry);
}
//processData()的具体实现 交给zxing
 @Override
public String processData(byte[] data, int width, int height, boolean isRetry) {
    String result = null;
    Result rawResult = null;
    Log.e("scan","processData");
    try {
        PlanarYUVLuminanceSource source = null;
        Rect rect = mScanBoxView.getScanBoxAreaRect(height);
        if (rect != null) {
            source = new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect.height(), false);
        } else {
            source = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false);
        }
        rawResult = mMultiFormatReader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source)));
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        mMultiFormatReader.reset();
    }

    if (rawResult != null) {
        result = rawResult.getText();
    }
    return result;
}

zxing内部交给了 zxing :compile 'com.google.zxing:core:3.3.1' 来计算

1945010-53b48b3722c12843.png

本项目还有些优化的地方

  1. 弱光打开自动打开闪光灯
    可参考: http://blog.csdn.net/PRIMEZPY/article/details/78628030
    2.扫描自动放大功能

你可能感兴趣的:(二维码、条形码扫描)