@zxing/library 实现分割二维码识别

899 阅读3分钟

背景

最近收到一个新的需求,需要在前端做一个读取二维码的功能,其中有一组二维码是分割二维码,也就是说我们拿到数据之后需要将二维码的信息按照先后顺序去组合成一条数据。听起来好像问题并不是很复杂,然后就在是着手调调研。

需求

我们先来捋一下需求信息

  1. 从一组二维码列表中,读取其中的三个二维码做组合组合为一个二维码
  2. 根据每个二维码的前12个bit数去判断,先后顺序

判断规则

1bit ~ 4bit:代表该二维码是否分割二维码 
5bit ~ 8bit: 代表该二维码再分割二维码中的排序
9bit ~ 12bit: 代表是否是同一个分割二维码

1bit ~ 4bit为'0011'时, 代表是分割二维码
9bit ~ 12bit 为 "0010"时,代表是同一个分割二维码

5bit ~ 8bit 为 "0000", 该二维码的排序为第1位
5bit ~ 8bit 为 "0001", 该二维码的排序为第2位
5bit ~ 8bit 为 "0010", 该二维码的排序为第3

方案调查

  • jsqr(不符合)
  • @zxing/library 首先我考虑到进行判断的二进制数据是由二维码扫描出来的内容转换而来的,所以采用了最基本的二维码jsqr的二维码扫描库信息,但是在实际的测试中发现并不是这样的,二维码的文本内容转换出来的二进制说跟基础的规则是完全匹配不上。

所以我们采用了 @zxing/library 库,这个库在扫描二维码的时候,除了可以扫描出来二维码的内容,还可以返回二维码数据流,转为二进制内容,对比规则刚好是可以与匹配上。

在@zxing/library扫描二维码之后可以获取字节数据,进而取得对应的二进制信息

result.getRawBytes()

方案实现

这里我们就直接上代码了

  • 引入插件
yarn add @zxing/library
  • html加入一个标签
// id后边会用到,修改需要注意
 <video id="video" autoPlay></video>
  • 初始化一个全局管理数据
import { BrowserMultiFormatReader, Exception, Result } from '@zxing/library';
import { CodeResult } from './index.d';

type codeResultCallback = (data: CodeResult) => {};

// 全局管理器
let codeReader: BrowserMultiFormatReader | null = null;
// 回调数据信息
let resultCallback: codeResultCallback;

// 导出初始化相机
export const initScan = (callback: codeResultCallback) => {
  resultCallback = callback;
  codeReader = new BrowserMultiFormatReader();
  openScan()
  return codeReader;
}
  • 打开摄像机
// 获取摄像机信息
const openScan = async () => {
  codeReader?.listVideoInputDevices().then((mediaDeviceInfo) => {
    console.log('videoInputDevices', mediaDeviceInfo);
    // 默认获取第一个摄像头设备id
    let firstDeviceId = mediaDeviceInfo[0].deviceId;
    // 获取第一个摄像头设备的名称
    const videoInputDeviceslablestr = JSON.stringify(mediaDeviceInfo[0].label);
    if (mediaDeviceInfo.length > 1) {
      // 判断是否后置摄像头
      if (videoInputDeviceslablestr.indexOf('back') > -1) {
        firstDeviceId = mediaDeviceInfo[0].deviceId;
      } else {
        firstDeviceId = mediaDeviceInfo[1].deviceId;
      }
    }
    decodeFromInputVideoFunc(firstDeviceId);
  }).catch(err => {
    // this.tipShow = false;
    console.error(err);
  });
}
  • 开启扫描设备
const decodeFromInputVideoFunc = (firstDeviceId: string) => {
  codeReader?.reset(); // 重置
  codeReader?.decodeFromVideoDevice(firstDeviceId, 'video', (result: Result, err?: Exception) => {
    if (result) {
      console.log(result.getNumBits());
      const uint8String = toUint8String(result.getRawBytes());
      resultCallback({ data: {result, uint8String}});
    }
  });
}

  • 字节数组转为二进制
const toUint8String = (bytes: Uint8Array) => {
  let uint8String = "";
  for (const b of bytes) {
    uint8String += b.toString(2).padStart(8, "0");
  }
  return uint8String;
}
  • 关闭摄像机
codeReader.reset();
codeReader = null;
  • 重置扫描
codeReader?.reset(); 

完结

首次写文章不知道该怎么写了,就写这么多吧。欢迎在评论区一起交流

参考文章: blog.csdn.net/weixin_4880…