Android 二维码的集成及优化

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值