Android 两种扫码效率高的扫码工具对比:QrCodeScanner和QrCodeScan
1. 前景介绍
Android二维码扫描大多采用Zxing和Zbar扫码库,但是两个扫码库都各有缺点
Zxing:
1.ZXing是Java写的,对二维码的解析效率没有ZBar快
2.有效扫描区域不好控制
3.原始代码是横屏模式,尽管可以改成竖屏,但是扫描界面的自定义和多屏幕适配不好做
Zbar:
1. ZBar是C实现的二维码解析,但是在解析中文时会乱码
2. ZBar的扫描界面对相机的控制没有ZXing封装的好
根据这些情况,大神们用ZXing来控制摄像头取得图像,用ZBar来解析扫描到的数据,QrCodeScanner和QrCodeScan扫码工具就应运而生,使用情况略有不同,也各有优点。
2. 对比两个扫码库
QrCodeScanner整体效率超赞,市面上的二维码都能快速识别,唯一缺点就是集成会增加app大小;QrCodeScan相对效率不如QrCodeScanner,但是也是很快的,存在个别二维码识别速率较慢,比如QQ钱包的付款码,集成时对app影响不大。
大家根据需求使用。本文介绍QrCodeScanner的使用
3. 集成过程
3.1.添加so文件,将so文件拷贝到如图位置,并在app的build.gradle的android下添加:
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
3.2.将Demo中的com.duoyi中的所有文件按照如图的目录结构,拷贝到自己的项目中(注意:一定按照Demo中的目录结构)
3.3.添加项目中缺少的文件,把Demo中的文件拷贝过来
3.4.在一般项目中,点击了按钮才会触发扫描二维码,在这里我使用了Rxjava的获取动态权限的方式:
3.4.1 在app的build.gradle中添加依赖:
compile 'io.reactivex:rxjava:1.1.9'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'
compile 'com.tbruyelle.rxpermissions:rxpermissions:0.9.1@aar'
3.4.2 Rxpermissions结合Rxbinding获取动态权限:
RxView.clicks(findViewById(R.id.main_btn))
.compose(new RxPermissions(this).ensure(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE))
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean granted) {
if (granted){
//获取了权限
startActivity(new Intent(MainActivity.this, CaptureActivity.class));
}else{
//没有获取权限
}
}
});
4. 性能优化
4.1.调整扫描采样区域,优化取图速度
在CameraManager类中不改变扫码框大小,获取屏幕大小,然后根据屏幕宽度由中间截取于宽度等长的正方形,根据图片分辨率和屏幕分辨率截取实际大小的图片区域
public Rect getRealFramingRect() {
if (realFramingRect == null) {
//获取屏幕大小,然后根据屏幕宽度由中间截取于宽度等长的正方形
Point screenResolution = configManager.getScreenResolution();
int leftOffset = 0;
int topOffset = (screenResolution.y - screenResolution.x) / 2;
Rect rect = new Rect(leftOffset, topOffset, screenResolution.x,
screenResolution.x+topOffset);
//根据图片分辨率和屏幕分辨率截取实际大小的图片区域
Point cameraResolution = configManager.getCameraResolution();
rect.left = rect.left * cameraResolution.y / screenResolution.x;
rect.right = rect.right * cameraResolution.y / screenResolution.x;
rect.top = rect.top * cameraResolution.x / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
realFramingRect = rect;
}
return realFramingRect;
}
4.2.获取适配的摄像头预览图片,防止图片拉伸
在CameraConfigurationManager类中获取摄像头所有预览尺寸,根据屏幕分辨率选取最适合的预览尺寸。
private static Point findBestPreviewSizeValue(
CharSequence previewSizeValueString, Point screenResolution) {
int bestX = 0;
int bestY = 0;
int diff = Integer.MAX_VALUE;
//previewSizeValueString为包含所有预览尺寸的字符串
for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
previewSize = previewSize.trim();
int dimPosition = previewSize.indexOf('x');
if (dimPosition < 0) continue;
try {
int newX = Integer.parseInt(previewSize.substring(0, dimPosition));
int newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
if (newDiff == 0) {
bestX = newX;bestY = newY;
break;
} else if (newDiff < diff) {
bestX = newX;bestY = newY;diff = newDiff;
}
} catch (NumberFormatException nfe) {
continue;
}
}
if (bestX > 0 && bestY > 0) {
return new Point(bestX, bestY);
}
return null;
}
5. 源码分析
如果这个二维码扫描界面不是你想要的,不妨在以下几个地方进行相应的修改:
5.1 扫描区域大小的调整:默认扫描区域是个正方形,边长是屏幕宽度的3/4,可以在CameraManager中的getFramingRect()方法中修改:
public Rect getFramingRect() {
Point screenResolution = configManager.getScreenResolution();
if (framingRect == null) {
if (camera == null) {
return null;
}
//这个设置扫描区域的大小
int width = screenResolution.x * 3 / 4;
if (width < MIN_FRAME_WIDTH) {
width = MIN_FRAME_WIDTH;
} else if (width > MAX_FRAME_WIDTH) {
width = MAX_FRAME_WIDTH;
}
int height = width;
if (height < MIN_FRAME_HEIGHT) {
height = MIN_FRAME_HEIGHT;
} else if (height > MAX_FRAME_HEIGHT) {
height = MAX_FRAME_HEIGHT;
}
int leftOffset = (screenResolution.x - width) / 2;
int topOffset = (screenResolution.y - height) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width,
topOffset + height);
}
return framingRect;
}
5.2 扫描区域的边角—八个竖线的样式的调整
//这里控制八个竖线的宽度
private static final int CORNER_WIDTH = 10;
在自定义控件ViewfinderView中的onDraw方法中进行了八个竖线的绘制
//画笔的颜色,八个竖线和扫描线
paint.setColor(Color.GREEN);
//这里是八个竖线的位置 CORNER_WIDTH:八个竖线的宽度
canvas.drawRect(frame.left, frame.top, frame.left + ScreenRate,
frame.top + CORNER_WIDTH, paint);
canvas.drawRect(frame.left, frame.top, frame.left + CORNER_WIDTH,
frame.top + ScreenRate, paint);
canvas.drawRect(frame.right - ScreenRate, frame.top, frame.right,
frame.top + CORNER_WIDTH, paint);
canvas.drawRect(frame.right - CORNER_WIDTH, frame.top, frame.right,
frame.top + ScreenRate, paint);
canvas.drawRect(frame.left, frame.bottom - CORNER_WIDTH, frame.left
+ ScreenRate, frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom - ScreenRate, frame.left
+ CORNER_WIDTH, frame.bottom, paint);
canvas.drawRect(frame.right - ScreenRate, frame.bottom
- CORNER_WIDTH, frame.right, frame.bottom, paint);
canvas.drawRect(frame.right - CORNER_WIDTH, frame.bottom
- ScreenRate, frame.right, frame.bottom, paint);
其中,frame 就是扫描区域的矩形
Rect frame = CameraManager.get().getFramingRect();
5.3 扫描线样式调整
//这里控制重新绘制的频率
private static final long ANIMATION_DELAY = 10L;
//这里控制扫描线的宽度
private static final int MIDDLE_LINE_WIDTH = 6;
//这里控制扫描线距离边界的距离
private static final int MIDDLE_LINE_PADDING = 5;
//这里控制扫描线速率
private static final int SPEEN_DISTANCE = 5;
同样是在ViewfinderView中的onDraw方法中进行的绘制
canvas.drawRect(frame.left + MIDDLE_LINE_PADDING, slideTop
- MIDDLE_LINE_WIDTH / 2, frame.right - MIDDLE_LINE_PADDING,
slideTop + MIDDLE_LINE_WIDTH / 2, paint);
以上就是使用QrCodeScanner集成二维码扫描的过程
谢谢:
http://www.jianshu.com/p/4d70b286f42f
奉上Demo:
https://github.com/Mr-zhang0101/MyQrCodeScanner.git