介绍
Zxing库是目前在Android开发中使用率比较高的一维/二维码识别的开源库。相较于实现了同样功能的Zbar库,Zxing的所有功能都是通过Java代码实现的,这点对于Android开工程师来说很友好。另外由于Zbar的开源项目长期没人维护,所以如果出现问题或者需要做定制,会非常困难。
下面会根据自己在实际项目中针对Zxing库的定制和修改,主要对Zxing库的二维码识别的流程以及核心源码进行解读,一维码的解析流程比较简单,不做介绍。由于能力有限,会指出核心方法中算法的意义,但是不会深究解读其中的算法实现。
流程图
核心类说明及核心方法分析
LuminanceSource
我们在使用Zxing时,首先要获得一张/一帧图片的位图数据,也就是一个byte数组,然后将图片信息传递给LuminanceSource。这个类的主要功能将我们传入的图片数据裁剪为一个只含有识别区域数据的矩形。
LuminanceSource是一个抽象类,下面有三个子类,三个子类是根据我们传入的数据源的不同进行分类的,其功能如下:
- RGBLuminanceSource :传入的流数据格式为RGB类型,主要应用场景是解析本地文件。
- PlanarYUVLuminanceSource :传入的流数据格式为YUV类型,主要应用场景是解析摄像头返回的数据。
- InvertedLuminanceSource : 将传入的数据进行旋转,外部一般不会调用。
这三个类中,我们拿PlanarYUVLuminanceSource来看看他的构造方法(RGBLuminanceSource与其类似):
public PlanarYUVLuminanceSource(byte[] yuvData, //传入的帧数据
int dataWidth, //数据源图片宽度
int dataHeight, //数据源图片高度
int left, //识别区域的左边距
int top, //识别区域的上边距
int width, //识别区域的宽度
int height, //识别区域的高度
boolean reverseHorizontal //是否需要旋转图片
)
在这个构造方法中,我们一般不会使用到reverseHorizontal这个参数,默认传false,需要我们注意到的参数是left和top,因为这两个参数是裁剪区域相对于传入流的位置,而摄像头返回的流数据可能是横屏或者竖屏的,在不对流进行旋转操作的前提下,这两个参数在传值时是不同的,具体说明可查看下面的 注意事项。
这个类的核心方法有两个:
- getMatrix() : 获取裁剪后的二维的位图数据
- getRow() : 获取裁剪后某一行的位图数据
上面的后两个是核心方法,其核心代码和说明如下:
@Override
public byte[] getRow(int y, byte[] row) {
//数据纠错
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
//创建一个空的裁剪区域大小的数组
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
//计算裁剪区域的偏移量
int offset = (y + top) * dataWidth + left;
//从流数据中取出对应裁剪区域,指定行的位图数据
System.arraycopy(luminances, offset, row, 0, width);
return row;
}
@Override
public byte[] getMatrix() {
int width = getWidth();
int height = getHeight();
//如果发现不需要裁剪,直接返回
if (width == dataWidth && height == dataHeight) {
return luminances;
}
//创建一个空的裁剪区域大小的数组
int area = width * height;
byte[] matrix = new byte[area];
//计算裁剪区域的偏移量
int inputOffset = top * dataWidth + left;
//如果不在x轴上进行裁剪
if (width == dataWidth) {
System.arraycopy(lumina