Android 二维码的集成及优化

来源:互联网 发布:nat123映射阿里云域名 编辑:程序博客网 时间:2024/06/11 15:56

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']        }    }

添加so文件

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

0 0
原创粉丝点击