zxing是一款跨平台的基于Java完成的处理一维或二维条码的库。支撑多种格局,一维条码支撑UPC-A,UPC-E,EAN-8,Code 39,Code 93等格局,二维条码支撑QR Code,Data Matrix,PDF 417,MaxiCode等格局。

注:上述的二维条码指的是较宽泛的二维条码,而不是QR Code表明的二维码。

前语

本来Lark直接集成了zxing完成扫一扫功用。因为Lark的特殊事务需求,因而并不需求支撑到这么多格局,只需求支撑QR Code,因而咱们对zxing内部进行定制,使得zxing只支撑QR Code。这样既能够削减zxing库的巨细,也能够加速zxing处理一帧数据的速度。优化主要包括两方面:(1)扫描性能(2)交互体会。

扫描性能优化包括:

  • 去除zxing额定支撑的格局。

  • 删去zxing冗余代码。

  • 将处理相机帧从串行改为并行。

交互体会优化包括:

  • 自动放大。

  • 双击放大。

  • 重力传感器聚集。

  • 手势调整焦距。

去除zxing额定支撑的格局

MultiFormatReader的decodeWithState( )是使用方的进口办法,内部调用了decodeInternal( ),输入是相机的一帧数据,假如抛了NotFoundException,则表明没找到二维码;假如回来了Result,则表明找到了二维码,并解析完成。代码如下:

其中,readers变量是一个数组,数组的巨细表明支撑的条码格局个数,zxing本来因为支撑许多格局,因而这个数组长度比较长。当拿到相机的一帧数据后,需求去检测是否是一切支撑格局的某一个格局,每一种格局的检测都需求花费一些时刻,因而这个遍历关于Lark是不必要的。假如将zxing内部定制成只支撑QR Code格局,那么就免去了额定的格局检测。

删去zxing冗余代码

咱们主要从几方面删去冗余代码:

  • 删去zxing除了二维码之外的格局的相关代码,zxing对每种格局的相关代码都放在各自的目录中,因而咱们只需求把这些格局对应的目录删去即可,比方aztec、maxicode等。

  • 删去二维码的encode相关代码,即”qrcode/encoder”目录。

  • 删去decode后文本的解析相关类(比方地址、通讯录、邮件等解析类),只保留URI、URL、Text。

经过以上方法,zxing文件数量从263个缩减到67个,库巨细从1.8M缩减到451K,作用非常显着。

将处理相机帧从串行改为并行

本来Lark扫一扫的逻辑是串行的,如下图:

每次从onPreviewFrame()中获取一帧数据,然后调用zxing的decode解析二维码,假如成功,则回来;假如失利,则调用setOneShotPreviewCallback( )重新调用一次onPreviewFrame( )。

缺陷是假如处理一帧数据时刻很长,会阻止下一帧的处理,比方上一帧是没有二维码的,而下一帧是有二维码的,假如上一帧处理时刻较长,那么虽然用户对准了二维码,可是实际处理的仍是上一帧,因而不太合理。

咱们将串行处理改成并行处理,一旦从onPreviewFrame( )获取一帧数据,将decode使命丢进线程池,并立即调用setOneShotPreviewCallback( )获取下一帧数据。一旦某个使命检测到二维码,立即将isSuccess变量置为true,忽略其他使命。这样能够大大加速二维码检测的速度。

自动放大

当二维码很小很远时,自动放大能大大加速检测二维码的速度。QRCodeReader的decode( ) 是二维码检测的主办法,分为两步:(1)大致判别是否存在二维码;(2)解码。

第一步仅仅检测是否存在二维码,比方去寻觅是否存在Position Detection Pattern,Timing Pattern,Alignment Pattern。假如检测到了,则回来DetectorResult,内部包括了定位点的位置信息;假如没检测到,则抛出NotFoundException。假如二维码很小,即使第一步检测存在二维码,可是第二步解码也可能会失利。因为咱们在第一步现已能够知道二维码的巨细,因而根据DetectorResult回来的二维码定位点信息计算出二维码的大致宽度,然后判别二维码巨细在扫码框中是否满足小,假如满足小,则放大一定焦距:假如小于十分之一,则放大到最大焦距;假如小于等于六分之一,则放大到最大焦距的一半。

详细二维码的原理参见:二维码的生成细节和原理(见原文链接)

咱们完成了zoomCamera( ),假如判别需求放大,则回来true,假如不需求放大,则回来false。代码如下:

咱们在第一步和第二步中心刺进该办法,假如需求放大,则不履行第二步;假如二维码现已满足大,则履行第二步。代码如下:

双击放大

本来Lark的二维码扫描中没有调整焦距的功用,这个关于一些特定场景下会不太方便,因而这里加入了双击放大的功用能够对焦距进行粗略的调整。使用GestureDetector的onDoubleTap()回调捕捉用户双击事情,并在CameraPreview中的onTouchEvent()中添加mGestureDetector.onTouchEvent()。完成如下:

重力传感器聚集

重力传感器能够捕捉用户手机的运动状况,当检测到用户手机中止时,触发对焦逻辑。咱们经过完成SensorEventListener接口,并重写onSensorChanged()监听手机的运动状况。

手势调整焦距

为了更精细化的让用户调整焦距,咱们供给了手势来缩放焦距。经过在onTouchEvent()中获取用户两个手指的间隔是越来越近仍是越来越远来调整焦距。代码如下:

优化结果

经过上述优化,不只增加了用户体会,而且还大幅增加了二维码扫描速度。测验手机:坚果Pro,4G内存,Android 7.1.1。


上图表明了从打开相机到二维码解码成功的耗时,能够看出,全体时刻提升了300%+ 。

上图表明检测失利时的耗时指的是当相机帧中没有二维码时检测的时刻,检测失利耗时的削减有助于更快地处理相机帧数据,当包括二维码的帧出现时更快地处理它;上图中看出,耗时削减300%+ 。

上图表明检测成功时的耗时指的是当相机帧中有二维码时检测+解码的时刻;上图中看出,耗时削减150%+ 。