• 技术文章 >微信小程序 >小程序开发

    如何利用小程序的canvas来绘制二维码?

    青灯夜游青灯夜游2022-01-06 10:14:37转载149
    微信小程序如何生成二维码?下面本篇给大家介绍一下利用小程序的canvas能力绘制二维码的方法,希望对大家有所帮助!

    在微信小程序的业务中会有一些需要展示二维码的场景。静态二维码可以直接存放在本地,使用图片方式展示,但不适合根据用户相关信息生成动态的二维码。本文将介绍下利用小程序的canvas能力绘制二维码。

    1 方法一:通过wx-qr直接生成

    1.1 DEMO

    微信开发者工具打开查看

    1.png
    含背景图
    2.png
    含logo
    3.png
    含logo+背景图

    1.2 安装

    # 通过 npm 安装
    npm i wx-qr -S
    
    # 通过 yarn 安装
    yarn add wx-qr

    1.3 使用组件

    首先在你所开发的小程序根目录 app.json 或需要使用该组件的 xxx.json 中引用组件

    (注意:请不要将组件命名为 wx-xxx 开头,可能会导致微信小程序解析 tag 失败 )

    {
      "usingComponents": {
        "qr-container": "wx-qr"
      }
    }

    之后就可以在 wxml 中直接使用组件

    <qr-container text="{{qrTxt}}" size="750"></qr-container>
    Page({
        data: {
            qrTxt: 'https://github.com/liuxdi/wx-qr',
        },
    });

    当然,还可以支持很多种配置,详见github 或者 码云文档。

    2. 方式二:基于QRCode.js结合canvas绘制

    2.0 二维码的组成部分

    4.png

    定位图案
    • Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。

    • Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。

    • Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。

    功能性数据
    • Format Information 存在于所有的尺寸中,用于存放一些格式化数据的。

    • Version Information 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。

    数据码和纠错码
    • 除了上述的那些地方,剩下的地方存放 Data Code 数据码 和 Error Correction Code 纠错码。

    2.1 引入二维码数据生成库

    复制qrcode.js至你的小程序相应目录。

    2.2 小程序中建立canvas标签,并给canvas设置长宽

    <canvas id="qr" type="2d" style="height: 750rpx;width: 750rpx;"></canvas>

    2.3获取canvas实例及上下文

    const query = this.createSelectorQuery();
    let dpr = wx.getSystemInfoSync().pixelRatio;
    query.select('#qr').fields({ node: true, size: true, id: true })
      .exec((res) => {
        let { node: canvas, height, width } = res[0];
        let ctx = canvas.getContext('2d');
        canvas.width = width * dpr
        canvas.height = height * dpr
        ctx.scale(dpr, dpr);
      })

    2.4 定义一些变量及绘制二维码的数据码区

    其中QRCodeModel是从qrCode.js中导入的

    // 二维码的颜色
    const colorDark = '#000';
    // 获取二维码的大小,因css设置的为750rpx,将其转为px
    const rawViewportSize = getPxFromRpx(750);
    // 二维码容错率{ L: 1, M: 0, Q: 3, H: 2 }
    const correctLevel = 0;
    // 创建二维码实例对象,并添加数据进行生成
    const qrCode = new QRCodeModel(-1, correctLevel);
    qrCode.addData(url);
    qrCode.make();
    
    // 每个方向的二维码数量
    const nCount = qrCode.moduleCount;
    // 计算每个二维码方块的大小
    const nSize = getRoundNum(rawViewportSize / nCount, 3)
    // 每块二维码点的大小比例
    const dataScale = 1;
    // 计算出dataScale不为1时,每个点的偏移值
    const dataXyOffset = (1 - dataScale) * 0.5;
    // 循环行列绘制数据码区
    for (let row = 0; row < nCount; row++) {
      for (let col = 0; col < nCount; col++) {
        // row 和 col 处的模块是否是黑色区
        const bIsDark = qrCode.isDark(row, col);
        // 是否是二维码的图案定位标识区 Position Detection Pattern(如本模块,是三个顶点位置处的大方块)
        const isBlkPosCtr = (col < 8 && (row < 8 || row >= nCount - 8)) || (col >= nCount - 8 && row < 8);
        // 是否是Timing Patterns,也是用于协助定位扫描的
        const isTiming = (row == 6 && col >= 8 && col <= nCount - 8) || (col == 6 && row >= 8 && row <= nCount - 8);
        // 如果是这些区域 则不进行绘制
        let isProtected = isBlkPosCtr || isTiming;
        // 计算每个点的绘制位置(left,top)
        const nLeft = col * nSize + (isProtected ? 0 : dataXyOffset * nSize);
        const nTop = row * nSize + (isProtected ? 0 : dataXyOffset * nSize);
        // 描边色、线宽、填充色配置
        ctx.strokeStyle = colorDark;
        ctx.lineWidth = 0.5;
        ctx.fillStyle = bIsDark ? colorDark : "rgba(255, 255, 255, 0.6)";
        // 如果不是标识区,则进行绘制
        if (!isProtected) {
          ctx.fillRect(
            nLeft,
            nTop,
            (isProtected ? (isBlkPosCtr ? 1 : 1) : dataScale) * nSize,
            (isProtected ? (isBlkPosCtr ? 1 : 1) : dataScale) * nSize
          );
        }
      }
    }

    此时已经绘制出二维码的数据码区:

    5.png

    2.5 绘制图形识别区

    // 绘制Position Detection Pattern
    ctx.fillStyle = colorDark;
    ctx.fillRect(0, 0, 7 * nSize, nSize);
    ctx.fillRect((nCount - 7) * nSize, 0, 7 * nSize, nSize);
    ctx.fillRect(0, 6 * nSize, 7 * nSize, nSize);
    ctx.fillRect((nCount - 7) * nSize, 6 * nSize, 7 * nSize, nSize);
    ctx.fillRect(0, (nCount - 7) * nSize, 7 * nSize, nSize);
    ctx.fillRect(0, (nCount - 7 + 6) * nSize, 7 * nSize, nSize);
    ctx.fillRect(0, 0, nSize, 7 * nSize);
    ctx.fillRect(6 * nSize, 0, nSize, 7 * nSize);
    ctx.fillRect((nCount - 7) * nSize, 0, nSize, 7 * nSize);
    ctx.fillRect((nCount - 7 + 6) * nSize, 0, nSize, 7 * nSize);
    ctx.fillRect(0, (nCount - 7) * nSize, nSize, 7 * nSize);
    ctx.fillRect(6 * nSize, (nCount - 7) * nSize, nSize, 7 * nSize);
    ctx.fillRect(2 * nSize, 2 * nSize, 3 * nSize, 3 * nSize);
    ctx.fillRect((nCount - 7 + 2) * nSize, 2 * nSize, 3 * nSize, 3 * nSize);
    ctx.fillRect(2 * nSize, (nCount - 7 + 2) * nSize, 3 * nSize, 3 * nSize);
    // 绘制Position Detection Pattern 完毕
    
    // 绘制Timing Patterns
    const timingScale = 1;
    const timingXyOffset = (1 - timingScale) * 0.5;
    for (let i = 0; i < nCount - 8; i += 2) {
      _drawDot(ctx, 8 + i, 6, nSize, timingXyOffset, timingScale);
      _drawDot(ctx, 6, 8 + i, nSize, timingXyOffset, timingScale);
    }
    // 绘制Timing Patterns 完毕

    这时候,一个朴素的二维码就绘制成功啦~

    6.png

    具体代码详见微信小程序代码片段

    https://developers.weixin.qq.com/s/WHJj73mX7bwv

    该代码只是提供了一个简单二维码的生成逻辑。若需要更复杂的二维码展示功能,还是建议使用wx-qr或参考里面的具体代码。欢迎各位提Issue和Star~~

    【相关学习推荐:小程序开发教程

    以上就是如何利用小程序的canvas来绘制二维码?的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    上一篇:一个邮箱可以有几个微信小程序 下一篇:手把手带你在小程序中怎么实现3d裸眼轮播效果

    相关文章推荐

    • 浅析小程序中如何优雅地进行模块化处理?• 手把手带你看看小程序如何优化?(实践总结)• 怎么从微信卡包跳转到小程序?实现方法浅析• 小程序大小超限除了分包还能怎么做?如何避免和解决大小限制?• 微信小程序是啥意思• 一个邮箱可以有几个微信小程序

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网