Just so so
8/13
2017

Zxing Camera 调用代码解析

Zxing 是一个开源的,支持多种一维二维条码格式的图像处理类库,用 JAVA 实现,支持多种语言接口。同时提供了 android 摄像头调用相关类库,用于手持设备的扫码解码。

本文主要介绍了 Android 系统调用 Camera 实现扫码的过程解析。

目录及相关类

  • activity: 扫码相关Activity
    • CaptureActivity: 扫码主界面Activity
    • CaptureFragment: 承载预览界面SurfaceView 和取景框 ViewfinderView
  • camera: 摄像头调用相关类
    • AutoFocusCallback: 自动对焦后回调类
    • CameraConfigurationManager: Camera 配置管理与初始化
    • CameraManager: 封装了 Camera 操作相关方法,例如获取Camera图像,请求自动对焦等
    • PreviewCallback: 预览图像发生变化时的回调类
  • decoding: 解码相关类
    • CaptureActivityHandler: CaptureActivity 回调类,处理各种消息,例如:解码成功失败,对焦,请求预览图像等
    • DecodeHandler: 解码回调类,解码处理类,封装了调用 Zxing-core 的方法
    • DecodeThread: 解码线程,会根据解码类型调用 DecodeHandler
  • view : CaptureFragment中控件
    • ViewfinderView: 取景框控件,绘制取景器,扫描线等

扫码过程

  • new CaptureActivity,初始化摄像头参数
  • new DecodeThread, 开始获取预览图像
decodeThread.start();
state = State.SUCCESS;
// Start ourselves capturing previews and decoding.
CameraManager.get().startPreview();
restartPreviewAndDecode();
  • 初始化PreviewCallback, 开始自动对焦, 绘制取景框
state = State.PREVIEW;      
CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
fragment.drawViewfinder();
  • 循环执行自动对焦,获取预览图像到CaptureFragment
  • 当预览图象发生变化时,会调用 PreviewCallback 中 onPreviewFrame() 方法, 获取图像 data 并发送 message 给DecodeHandler
Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,cameraResolution.y, data);
message.sendToTarget();
  • DecodeHandler 调用 decode 方法尝试解码,并发送解码结果message 给 CaptureActivityHandler。
if (rawResult != null) {
    long end = System.currentTimeMillis();
    Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
    Message message = Message.obtain(fragment.getHandler(), R.id.decode_succeeded, rawResult);
    Bundle bundle = new Bundle();
    bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
    message.setData(bundle);
    //Log.d(TAG, "Sending decode succeeded message...");
    message.sendToTarget();
} else {
    Message message = Message.obtain(fragment.getHandler(), R.id.decode_failed);
    message.sendToTarget();
}
  • CaptureActivityHandler 处理结果,解码失败继续尝试解码,解码成功返回结果进行跳转
if (message.what == R.id.decode_succeeded) {
        Log.d(TAG, "Got decode succeeded message");
        state = State.SUCCESS;
        Bundle bundle = message.getData();
        Bitmap barcode = bundle == null ? null :
                (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);

        fragment.handleDecode((Result) message.obj, barcode);

} else if (message.what == R.id.decode_failed) {

        state = State.PREVIEW;
        CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);