二维码扫描zxing库源码分析(一)
zxing简介
作为Google开源框架Zxing,功能很多,可以扫一维码二维码,二维码还支持多种格式,项目地址为https://github.com/zxing/zxing,目前zxing有多个人在维护,覆盖主流编程语言,也是目前还在维护的较受欢迎的二维码扫描开源项目之一。网上有很多关于zxing库如何集成到项目和如何精简的文章,大家可以自行百度;但是关于源码解析的很少,我主要做一些源码方面的解析,主要是图像处理相关的,如果你只是关心如何使用,那么这篇文章可能不太适合你。
(一)获取preview
1.我们可以看到CaptureActivity中创建好SurfaceHolder后调用了initCamera()这个方法,如果第一次打开相机那么使用cameraManager打开相机驱动,AutoFocusManager来自动聚焦。handler是获取到解析结果后返回给ui结果,我们可以在handler接收的地方获取到结果并做相应处理。
private void initCamera(SurfaceHolder surfaceHolder) {
、、、(代表省略若干)
try {
cameraManager.openDriver(surfaceHolder);
// Creating the handler starts the preview, which can also throw a
// RuntimeException.
if (handler == null) {
handler = new CaptureActivityHandler(CaptureActivity.this, decodeFormats,
decodeHints, characterSet, cameraManager);
}
decodeOrStoreSavedBitmap(null, null);
}
catch (IOException ioe) {
Log.w(TAG, ioe);
displayFrameworkBugMessageAndExit();
}
、、、
}
2.在cameraManager这个类里面, getFramingRectInPreview() 方法通过getFramingRect()方法限定矩形框然后将preview内容放到这样一个矩形框
,在cameraManager里面我们并没有发现是哪里开始获取预览图并开始解析的,但是我们发现了buildLuminanceSource()这个方法,我们发现它在DecodeHandler这个类里面调用,
private void decode(byte[] data, int width, int height) {
、、、
PlanarYUVLuminanceSource source = activity.getCameraManager()
.buildLuminanceSource(rotatedData, width, height);
、、、
我们发现decode方法处理的事byte数据,因此我们可以倒着找,看看谁调用了这个方法找到byte数据的来源。
(二)找到要decode的byte[]数据的来源
找了半天都没找到,然后想着从相机回调入手,找了PreviewCallback,发现了它
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Point cameraResolution = configManager.getCameraResolution();
Handler thePreviewHandler = previewHandler;
if (cameraResolution != null && thePreviewHandler != null) {
Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x, cameraResolution.y,
data);
message.sendToTarget();
previewHandler = null;
} else {
Log.d(TAG, "Got preview callback, but no handler or resolution available");
}
}
通过thePreviewHandler 将data信息发送了出去,而thePreviewHandler 是在CameraManager的requestPreviewFrame方法传进去的,在CaptureActivityHandler的handleMessage方法里面我们发现调用了cameraManager.requestPreviewFrame(decodeThread.getHandler(),
R.id.decode);这个方法,decodeThread.getHandler()这个方法实际上就是DecodeHandler,因此buildLuminanceSource()方法实际上就是对相机预览图的回调PreviewCallback的data进行处理。
(三)对byte[]型数据data的图像处理
DecodeHandler里面的decode()根据前后摄像机判断是否有需要旋转,旋转后调用CameraManager的buildLuminanceSource()方法,构造基于平面的YUV亮度源,即包含二维码区域的数据源,然后使用HybridBinarizer算法构造二值图像比特流并转化成bitmap(参考:http://blog.csdn.net/u012917700/article/details/52369175)。
调用multiFormatReader的decodeWithState方法对bitmap进行解析,multiFormatReader实际上是一个个的解码器,可以设置用到哪些解码器,比如常用的QR码解码器或者一维条形码,因为目前国内QR码用得最多,我们这里只研究QRCodeReader。
- 下一篇我们具体研究QRCodeReader对bitmap的解析。