一种压缩QRCode矩阵以用于存储的方法

通常QRCode由服务器生成,以图片格式发送到客户端,由客户端直接展示,也可以由客户端使用javascript或其他内置的SDK直接生成。

0、需求

QRCode生成过程中往往是先生成矩阵,然后使用矩阵生成图片,矩阵就是由01组成的一维或二维数组。

例如,由ZXing生成的ByteMatrix就是一个由行列数据组成的二维数组。

csharp 复制代码
//可以生成由01组成的一个矩阵字符串。
private string GetMatrixString(ByteMatrix matrix)
{
    return string.Join("", matrix.Array.Select(t => string.Join("", t)));
}

有时候,我们需要尽可能的减少网络传输,对QRCode进行缓存处理,或者减少QRCode矩阵生成的逻辑。

这时,我们完全可以将这个字符串发送给客户端,再由客户端生成图片,减少网络浏览传输或者方便客户端缓存QRCode。

下面方法可以对矩阵处理,生成QRCode图片。

javascript 复制代码
function createQRCodeCanvas(matrix, size, padding) {
  size = size || 3;
  padding = padding === undefined ? 3 : padding;
  const width = Math.sqrt(matrix.length);
  const canvasWith = width * size + padding * 2;

  const canvas = document.createElement('canvas');
  canvas.width = canvasWith;
  canvas.height = canvasWith;

  const ctx = canvas.getContext('2d');
  ctx.fillStyle = "rgb(0,0,0)";


  for (let y = 0; y < width; y++) {
    for (let x = 0; x < width; x++) {
      const point = y * width + x;
      if (matrix[point] === 1) {
        ctx.fillRect(padding + x * size, padding + y * size, size, size);
      }
    }
  }
  return canvas.toDataURL();
}
1、矩阵压缩

由于矩阵完全由01组成,我们可以对矩阵进行处理,每8位作为一组,转换成一个字节。

往往矩阵的长度不会被8整除,所以我们在最后一位补1,标识矩阵结束,哪怕矩阵长度能被8整除,我们也补1。

下面代码生成压缩后的矩阵字节数组。

csharp 复制代码
private byte[] GetMatrixBytes(ByteMatrix matrix)
{
    var qrData = matrix.Array;
    int idx = 7;
    int count = 0;
    byte[] result = new byte[(int)Math.Ceiling((decimal)(qrData.Length * qrData.Length + 1) / 8)];

    for (int i = 0; i < qrData.Length; i++)
    {
        byte[] line = qrData[i];
        for (int j = 0; j < line.Length; j++)
        {
            result[count++ >> 3] |= (byte)(line[j] << idx--);
            if (idx == -1) idx = 7;
        }
    }
    result[count >> 3] |= (byte)(1 << idx); //最后一位补1
    return result;
}

生成矩阵字节数组后,可以转换成base64发送到客户端,这样会大大减少传输的数据量。

2、矩阵还原

将上面的算法逆转即可。

例如,用csharp还原。

csharp 复制代码
/// <summary>
/// 从字节数组还原矩阵字符串
/// </summary>
/// <param name="matrix"></param>
/// <returns></returns>
private byte[] GetMatrixBytes(byte[] matrix)
{

    byte[] bytes = new byte[matrix.Length * 8];

    int idx = 0;

    foreach (byte chr in matrix) for (int i = 7; i >= 0; i--) bytes[idx++] = (byte)((chr >> i) & 1);

    while (bytes[--idx] == 0) ;

    return bytes.Take(idx).ToArray();
}

用javascript还原

javascript 复制代码
function getMatrix(raws) {

  const bytes = [];

  let idx = 0;

  for (let j = 0; j < raws.length; j++) {
    for (let i = 7; i >= 0; i--) bytes[idx++] = (raws[j] >> i) & 1;
  }

  while (bytes[--idx] === 0) ;

  return bytes.slice(0, idx);
}

矩阵还原出来后,就可以用文章最开始的方法将矩阵生成图片了。

3、总结

通过对矩阵的处理,进一步减少标识矩阵所用的字节数,从而减少网络传输的数据,并且更方便的缓存生成的QRCode。

客户端可以只缓存压缩后的矩阵,必要的时候还原并展示即可。

相关推荐
用户0044729538252 小时前
练歌镜:让眼镜听懂“循环这一句”
javascript
用户788477316345 小时前
WinForms 迁移 WPF:Upgrade Assistant 覆盖 30%,剩下 70% 我手写了六周
c#
yuyuxun15 小时前
协同过滤的校园二手物品智能推荐系统的设计与实现 毕业设计-附源码40082
javascript·vue.js·spring boot·python·数据分析·django·课程设计
总要学点什么8 小时前
第105篇:三维特效-流动图片墙体效果——让箭头沿墙长滚,它俩竟是同一份代码
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
寂寞的船9 小时前
【Unity知识速递】第13期 Unity 内存泄漏排查实战:从 Memory Profiler 到 Lua 引用泄漏的生产级全链路诊断
unity·junit·c#·游戏引擎·lua
Agent世界10 小时前
用 CDP 做发布自动化:四道机器闸门与产物验收
前端·javascript
总要学点什么10 小时前
第104篇:三维特效-流动墙体效果——让贴图沿墙流动,它却只肯走一条对角线
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
程序员大阳10 小时前
副队长ES6+教程(3)--解构赋值
前端·javascript·es6·赋值·解构
神膘护体小月半11 小时前
css - 元素背景图由 hover 触发,初次加载时闪动的解决办法
前端·javascript·css
程序员大阳11 小时前
副队长ES6+教程(2)--let 与 const
前端·javascript·es6·const·let·var