Git Product home page Git Product logo

smartscan's Introduction

SmartScan

SmartScan运用OpenGL从零打造一个依赖极低、高灵活、快速预览不变形ZXing扫码库,实现思路写在最后,喜欢的可以看下去。

  • 下面是演示效果,可直接下载试试 演示apk

旋转扫码演示 扫描途中变换参数

  • 依赖极低:

做一个老实的扫码库,权限判断应由应用自行判断;除去kotlin自身库仅依赖com.google.zxing:core:3.3.3,并且zxing:core用api方式依赖,方便引用。

  • 高灵活:
  1. 扫描线和扫描框可以是一张图片;扫描窗口大小可以设置相对高度、宽度的比例,也可以直接设置具体大小,窗口宽高比可变。同时提供属性在宽高不一致情况下约束为正方形(方便二维码扫描)。若还是不喜欢,可以把界面所有UI隐藏,然后这里提供窗口位置监听,在回调位置变化的时候自行设置自定义UI的位置
  2. 考虑到闪光灯的自定义程度比较高的问题,本库也提供一个默认实现,默认是关闭的,需要手动开启。如不喜欢可以自行定义,同时也提供闪光灯方法控制,即实现UI即可
  3. 扫码中途配置可变,可以在扫码途中更改扫码种类,扫码窗口大小等,所有参数均可改变
  4. 提供丰富的监听:结果监听(包括在UI线程、解码线程监听,同时也提供持续监听和监听到一个结果后停止)、图像数据监听、扫码窗口改变监听
  5. 灵活的创建方式,可从xml中创建,同时也能以代码的形式直接new出来
  • 快速预览不变形
  1. 为提高识别速度,针对一般扫码只用到二维码,也就是QR码,所以二维码部分仅保留QR识别,默认也仅开启QR识别。一维码种类较多,这里也提供,若需要仅使用一维码或二维码一维码同时使用,也提供相应的属性供设置
  2. 不必考虑是否全屏,保证预览图像不变形,处理好图像旋转问题,包括activity旋转的自动销毁创建问题、配置 android:configChanges="keyboardHidden|orientation|screenSize" 的时候,旋转不销毁问题、旋转180度surfaceChange无法监听问题
  • 该库使用方式(Kotlin Java):

在build.gradle加入依赖

implementation 'com.dming.glScan:smartscan:0.0.7'

若引用不上可在项目的build.gradle加上maven仓库地址,如下:

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://dl.bintray.com/dming/maven' }
    }
}

扫描框、扫描线、背景等基础UI已实现,若没有需求,开箱即用;若有定制,按需设置参数即可

xml创建:

<com.dming.glScan.SmartScanView
  android:id="@+id/smartScanView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:scanPercentTopOffset="0.2"
  app:scanPercentWidth="0.72"
  app:scanPercentHeight="0.55"
  app:enableFlashlightBtn="true"
  />

代码直接创建(Kotlin):

val smartScanView = SmartScanView(this)
val smartScanParameter = SmartScanParameter()
smartScanParameter.apply {
    this.scanPercentWidth = 0.65f
    this.scanPercentHeight = 0.65f
    this.scanPercentTopOffset = 0.2f
    this.enableFlashlightBtn = true
}
smartScanView.init(smartScanParameter)

代码直接创建(Java):

SmartScanView smartScanView = new SmartScanView(this);
SmartScanParameter smartScanParameter = new SmartScanParameter();
smartScanParameter.setScanPercentWidth(0.65f);
smartScanParameter.setScanPercentHeight(0.65f);
smartScanParameter.setScanPercentTopOffset(0.2f);
smartScanParameter.setEnableFlashlightBtn(true);
smartScanView.init(smartScanParameter);

动态改变配置(Kotlin):

val oneDP = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP, 1f,
    this.resources.displayMetrics
)
val smartScanParameter = smartScanView.getSmartScanParameter()
smartScanParameter.scanTopOffset = 80 * oneDP
smartScanParameter.scanWidth = 300 * oneDP
smartScanParameter.scanHeight = 300 * oneDP
smartScanParameter.scanLineWidth = 6 * oneDP
smartScanParameter.onlyOneDCode = false
smartScanParameter.enableFlashlightBtn = true
smartScanView.updateConfigure(smartScanParameter)    

动态改变配置(Java):

float oneDP = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP, 1f,
    this.getResources().getDisplayMetrics()
);
SmartScanParameter smartScanParameter = smartScanView.getSmartScanParameter();
smartScanParameter.setScanTopOffset(80 * oneDP);
smartScanParameter.setScanWidth(300 * oneDP);
smartScanParameter.setScanHeight(300 * oneDP);
smartScanParameter.setScanLineWidth(6 * oneDP);
smartScanParameter.setOnlyOneDCode(false);
smartScanParameter.setEnableFlashlightBtn(true);
smartScanView.updateConfigure(smartScanParameter);

监听结果(Kotlin):

smartScanView.setOnResultOnceListener(object : OnResultListener {
    override fun onResult(result: Result) {
        Toast.makeText(this@JavaCreateActivity,"result: ${result.text}",Toast.LENGTH_SHORT).show()
    }
})

监听结果(Java):

smartScanView.setOnResultOnceListener(new OnResultListener() {
    @Override
    public void onResult(Result result) {
        Toast.makeText(JavaCreateActivity.this,"result: "+result.getText(),Toast.LENGTH_SHORT).show();
    }
});

监听扫描框的位置变化,实现自定义UI重要监听器(Kotlin):

smartScanView.setScanViewChangeListener(object : OnScanViewListener {
   // surface创建的时候回调
   override fun onCreate() {
   }
   // 扫描窗口位置变化即回调
   override fun onChange(rect: Rect) {
   }
   // surface销毁的时候回调
   override fun onDestroy() {
   }
})

监听扫描框的位置变化,实现自定义UI重要监听器(Java):

smartScanView.setScanViewChangeListener(new OnScanViewListener() {
    // surface创建的时候回调
    @Override
    public void onCreate() {
    }
    // 扫描窗口位置变化即回调
    @Override
    public void onChange(Rect rect) {
    }
    // surface销毁的时候回调
    @Override
    public void onDestroy() {
    }
});
  • 参数配置大全:
class SmartScanParameter {
    // 扫描框宽度,单位像素
    var scanWidth: Float = 0f
    // 扫描框高度,单位像素
    var scanHeight: Float = 0f
    // 扫描框宽度百分比 0 - 1.0f
    var scanPercentWidth: Float = 0f
    // 扫描框高度百分比 0 - 1.0f
    var scanPercentHeight: Float = 0f
    // 扫描框距离头部偏移,单位像素
    var scanTopOffset: Float = 0f
    // 扫描框距离头部偏移,相对高度百分比 0 - 1.0f
    var scanPercentTopOffset: Float = 0f
    // 约束扫描框为正方形,将使用最短的边为边长,可用在扫描二维码,默认开启
    var scanMustSquare: Boolean? = null
    // 扫描线drawable,当存在时,优先使用
    var scanLine: Drawable? = null
    // 扫描框drawable,当存在时,优先使用
    var scanCorner: Drawable? = null
    // 扫描背景颜色,一般黑色透明
    var scanBackgroundColor: Int? = null
    // 是否加入一维码解码,默认为QR二维码解码,按需加入
    var addOneDCode: Boolean = false
    // 仅使用一维码解码
    var onlyOneDCode: Boolean = false
    // 扫描角颜色
    var scanCornerColor: Int? = null
    // 自定义扫描角长度
    var scanCornerSize: Float = 0f
    // 自定义扫描角线宽度
    var scanCornerThick: Float = 0f
    // 扫描线颜色
    var scanLineColor: Int? = null
    // 扫描线宽度大小
    var scanLineWidth: Float = 0f
    // 扫描线时间,单位毫秒
    var scanLineTime: Int? = null
    // 扫描框的细线宽度,一般1px
    var scanFrameLineWidth: Float? = null
    // 扫描框的细线颜色
    var scanFrameLineColor: Int? = null
    // 禁止窗口双指放大,默认开启
    var disableScale: Boolean = false
    // 使能滴一声的扫描成功声音
    var enableBeep: Boolean = false
    // 使能震动扫描成功
    var enableVibrate: Boolean = false
    // 使能闪光灯按钮,由于按钮位置图像可变性太强,默认是不开启的,由用户定制
    var enableFlashlightBtn: Boolean = false
}

XML参数也是同名,用法与上相同

<declare-styleable name="SmartScanView">
    <attr name="scanWidth" format="dimension" />
    <attr name="scanHeight" format="dimension" />
    <attr name="scanPercentWidth" format="float" />
    <attr name="scanPercentHeight" format="float" />
    <attr name="scanTopOffset" format="dimension" />
    <attr name="scanPercentTopOffset" format="float" />
    <attr name="scanLine" format="reference" />
    <attr name="scanCorner" format="reference" />
    <attr name="scanBackgroundColor" format="color" />
    <attr name="addOneDCode" format="boolean" />
    <attr name="onlyOneDCode" format="boolean" />
    <attr name="scanMustSquare" format="boolean" />
    <attr name="scanCornerSize" format="dimension" />
    <attr name="scanCornerThick" format="dimension" />
    <attr name="scanLineWidth" format="dimension" />
    <attr name="scanLineColor" format="color" />
    <attr name="scanLineTime" format="integer" />
    <attr name="scanFrameLineWidth" format="dimension" />
    <attr name="scanFrameLineColor" format="color" />
    <attr name="scanCornerColor" format="color" />
    <attr name="disableScale" format="boolean" />
    <attr name="enableBeep" format="boolean" />
    <attr name="enableVibrate" format="boolean" />
    <attr name="enableFlashlightBtn" format="boolean" />
</declare-styleable>
  • 以下为所有方法:

// 设置获取亮度(灰度)图片监听
setGrayImgListener
// 从解码线程中监听解码结果,会不断的触发,可使用stopDecode()关闭
setOnResultInThreadListener
// 从解码线程中监听解码结果,成功后会停止,可使用startDecode()开启
setOnResultOnceInThreadListener
// 从UI线程中监听解码结果,会不断的触发,可使用stopDecode()关闭
setOnResultListener
// 从UI线程中监听解码结果,成功后会停止,可使用startDecode()开启
setOnResultOnceListener
// 监听smart的扫码窗口改变,自定义窗口极奇重要的监听
setScanViewChangeListener
// 手动开启解码
startDecode
// 手动关闭解码
stopDecode
// 闪光灯开启关闭
setFlashLight
// 扫码过程中改变配置,如窗口大小,扫码类型等
updateConfigure
// 获取camera对象
getCamera

  • 实现思路:

Camera在GL线程开启,摄像头数据由该线程分别以亮度方式绘制到FBO和以原始图像方式绘制到预览界面,解码线程共享GL线程context,先绘制FBO中的亮度纹理数据,然后在绘制结果中读取像素,当然仅仅是读取设置的扫描窗口区域,然后进行解码。由于摄像头数据由自定义GL着色器绘制,可控性高,通过计算绘制出无变形的图像。ZXing解码过程需要转亮度,FBO中的纹理已经是亮度纹理,也就不用专门转亮度,算是提高了一丢丢的效率。考虑到activity旋转问题和surface的生命周期,surface在旋转、离开activity后会被销毁;既然surface销毁了,预览界面都没了,camera也就不必存在了,故把camera与surface捆绑起来,同生死。此外,剩下的问题就是摄像头旋转问题,这个需要拿getDefaultDisplay().getRotation()真实的旋转角度来计算出合适的旋转角度进行矫正。

smartscan's People

Contributors

dmings avatar

Stargazers

渣渣李 avatar onKotlin avatar  avatar ChrongLiu avatar Kang-zy avatar  avatar Fritz avatar 杨培星 avatar wangyibo avatar 祀画 avatar dujiang avatar 伊撒尔 avatar Karl avatar  avatar  avatar  avatar fanshanhong avatar ZhenYouLi avatar  avatar

Watchers

James Cloos avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.