今日笔者的公司因为二维码内容为hex字符串,并且内容过长,生成码后密度过大,导致终端扫码摄像头很难识别成功

现借用weapp-qrcode库以及一串hex字符串来说明压缩减半,以及如何将减半的数据传入库来生成码

长度压缩

首先我们有如下hex字符串

let str = '33496AA448F500E87D3F41EF41AB49C4C0047BC419BBA1FB1EEA5D80B6E181D6D39D9C'

java的同事说用byte[]处理,但js无这个接口去直接处理,经过与写c的同事讨论算法,以及下文观察库的源码,发现可以算出unicode值数组,直接放入库中生成码

压缩函数

function strtouint8array(str){
    let a = []            
    let b = (a) => {
        if(a >= 48 && a <= 57){
            a = a - 48
        }else if(a >= 65 && a <= 70){                 
            a = a - 65 + 10
        }
        return a
    }
    for(let i = 0; i < str.length / 2; i += 1){
        let [c, d] = str.substr(i * 2, 2),
            [e, f] = [c.charCodeAt(), d.charCodeAt()]  // hexString -> unicode
        a[i] = b(e) * 16 + b(f)                        // unicode压缩算法
    }
    return a                                           // 示例库修改源码后接受的为array
}

修改库生成码

在github查看weapp-qrcode库的说明,发现只能接收string来生成图片

笔者通过压缩后的unicode -> string再放入库中,生成的码依旧存在问题

通过观察库的源码,笔者发现其实库在接收string后,有个utf16to8的操作,并且在生成码之前,向QRBitBuffer中写入数据时,使用了类似的方法处理了string,并且使用了生成的unicode数组生成码

库源码示例:

//index.js 第8行

// support Chinese
function utf16to8 (str) {
  var out, i, len, c
  out = ''
  len = str.length
  for (i = 0; i < len; i++) {
    c = str.charCodeAt(i)
    if ((c >= 0x0001) && (c <= 0x007F)) {
      out += str.charAt(i)
    } else if (c > 0x07FF) {
      out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F))
      out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F))
      out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F))
    } else {
      out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F))
      out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F))
    }
  }
  return out
}

//qrcode.js 第35行

function QR8bitByte(data) {
  this.mode = QRMode.MODE_8BIT_BYTE;
  this.data = data;
}

QR8bitByte.prototype = {

  getLength : function(buffer) {
    return this.data.length;
  },
  
  write : function(buffer) {
    for (var i = 0; i < this.data.length; i++) {
      // not JIS ...
      buffer.put(this.data.charCodeAt(i), 8);
    }
  }
};

由于生成unicode过程在上文中,我们自己处理过,所以我们可以不使用库的方法,直接跳过库中utf16to8与转换成unicode的过程,并且将数据丢进去

所以我们可以将库修改为

//index.js 第8行

// support Chinese
function utf16to8 (str) {
  return str
}

//qrcode.js 第35行

function QR8bitByte(data) {
  this.mode = QRMode.MODE_8BIT_BYTE;
  this.data = data;
}

QR8bitByte.prototype = {

  getLength : function(buffer) {
    return this.data.length;
  },
  
  write : function(buffer) {
    for (var i = 0; i < this.data.length; i++) {
      // not JIS ...
      buffer.put(this.data[i], 8);
    }
  }
};

修改好之后,在此处命令行执行

npm insall    // 安装打包的依赖
npm run build // 构建文件

构建完后使用dist目录下的文件,并且在库的text接口传入压缩后unicode生成的array即可

在此感谢写c的同事@ 程淼

参考文档

weapp-qrcode

Last modification:August 30, 2019
If you think my article is useful to you, please feel free to appreciate