小程序菊花码定制化需求探讨:中间Logo替换及处理方案梳理

2025-06-21
来源:万象资讯

前言

小程序的菊花码识别度较高,与一般二维码相比,一眼便能辨认,只需用微信扫描即可。

在默认设置下,我们有权自行设定生成码的各项参数,包括路径、尺寸,并且可以自主选择线条颜色的自动或手动调整,同时也能决定底色是否采用透明效果。

然而,这些配置项往往是无法满足我们的定制化需求的。

以一个实例为证,我们得在确保小程序码识别度不受影响的前提下,对中间的标志进行更换,这该如何操作呢?下面,作者将亲自指导大家。

梳理思路

首先,我们需要深入分析这个问题的核心。实际上,这是一个关于图像处理的课题,且这项任务既可以在服务端完成,也可以在客户端进行。

于是就有 2 个方案:

提供端到端编码及结果整合的服务端解决方案。具体实施方法,感兴趣的朋友们,不妨阅读我的文章《Web 函数自定义镜像实战:构建图像处理函数》。

服务端生码,客户端缝合方案。这就是本篇文章具体提及的。

注:小程序码一般由服务端调用微信api接口生成

云调用——生码最简便方案

众所周知,微信小程序的构建模式分为两大类,一类是通过本地调用实现,另一类则是依托云端进行调用。

云调用作为一种针对特定场景设计的解决方案,通常能够显著提高我们的开发效率。我们计划迅速搭建一个函数,以此为我们提供必要的测试材料。

/.js:

引入云函数模块,源自“wx-server-sdk”,并初始化配置对象,具体操作如下: 在cloud.DYNAMIC_CURRENT_ENV环境变量控制下,导出一个名为main的异步函数,该函数接收两个参数:事件(event)和上下文(context)。 从事件中提取出以下参数:场景(默认为空字符串),页面,宽度(默认为430像素),自动着色,线条颜色,以及是否为半透明。     scene,     page,     width,     autoColor,     lineColor,     isHyaline   }) 使用打包工具后,若大家希望直接运行,只需将esm格式转换为cjs格式即可。

/.json:

{   "permissions": { "开放API接口包括:使用wxacode.getUnlimited方法获取无限二维码。"   }}

通过上述 2 段代码块,我们的测试函数就部署完成了。

把返回的

const suffixMap = { 图像文件类型为JPEG,其格式标识为jpeg。 定义一个导出函数,该函数名为getPath,它接受两个参数:filename默认值为'tmp',contentType默认值为'image/jpeg'。 返回`${wx.env.USER_DATA_PATH}/${filename}.${suffixMap[contentType]||'jpeg'}`,导出`writeFile`函数,该函数接收缓冲区`buff`,内容类型`contentType`默认为`'image/jpeg'`,文件名`filename`默认为`'tmp'`。 返回一个新的Promise对象,其中包含一个执行解析的回调函数resolve,以及一个执行拒绝的回调函数reject。 创建了一个常量fsm,该常量是通过调用wx.getFileSystemManager()方法获取的文件系统管理器。 filePath变量通过调用getPath函数,并传入filename和contentType参数来获取路径。     fsm.writeFile({       filePath,       data: buff, 编码格式:二进制类型,       success() {         resolve(filePath)       },       fail(error) {         reject(error)       }     })   })}....// 在需要用到的地方直接try {   loading('生成中')   console.error(e)} finally {   loaded()}

客户端的图像处理

提及客户端图像处理技术,便不能不提及其原生组件,因此,我们仅需借助该组件,对小程序码中的Logo区域进行精确测量与裁剪,进而替换为我们所定制的图像。

测量

在此以标准的小程序码尺寸为基准。(为了便于理解,本案例中均采用了这种分辨率的小程序码,若需要其他分辨率,则可按比例调整进行裁剪。)

小程序码标注

微信小程序开发封装路径数据_小程序码自定义Logo替换_微信小程序码图像处理

根据图中的标记信息,我们可以看出在特定分辨率中,四周的边距是固定的,据此可以计算出位于中心位置的Logo圆形的直径长度为,其半径则为95像素。

所以接下来就可以轻松愉快的写代码了。

利用 2d实现

第一代小程序API已经不再适用,目前应直接采用type="2d"的版本,相关Api文档可在MDN网站上查阅。

前置标签和样式

// scss .canvas.offscreen{//采用两个class选择器,提升其优先级设置}   position: absolute;   bottom: 0;   left: -9999rpx;   // 这叫物理离屏渲染,笑~ }

核心 js 实现

初始化实例和上下文

初始化 实例和 ctx 上下文:

canvas上创建上下文对象ctx,并执行包含相应代码的onReady函数。   uni     .createSelectorQuery() 若该组件包含canvas元素,则必须添加此行代码,以选择ID为'#canvas'的元素。     .fields({       node: true,       size: true     })     .exec((res) => {       if (res[0]) { 此画布变量被赋值为传入的canvas,同时与资源数组res的第一个元素的node属性相等。 根据设备的pixelRatio进行相应比例的调整,但在此处为了演示的便捷性,我们直接将canvas的宽度设置为430。         canvas.height = 430       }     })}

第一次渲染-画布背景

第一次渲染,把小程序码,作为图像传入画布。 :

同步执行绘制背景函数,参数为原始二维码链接。 此处可设定为远程地址(需设置downloadUrl),亦或是本地地址(可返回参数自行处理),甚至包括以cloud://为前缀的云存储链接,src字段则对应orginQrcodeUrl。   })   if (err) {     throw err   }   const { path } = res canvas上创建了一个新的图像实例,并将其赋值给变量img。   img.src = path 创建一个新的Promise对象,并在其中定义一个回调函数,该函数包含两个参数:resolve和reject,用于处理异步操作的完成或失败。     img.onload = () => { 将小程序码完整地绘制至画布之上,具体操作如下:将图片img按照其原始尺寸,从画布的左上角(坐标0,0)开始,填充至整个画布的宽度(canvas.width)和高度(canvas.height)。       resolve()     } 当图片加载失败时,设置其错误处理函数为箭头函数,该函数接受一个事件对象作为参数。       reject(event)     }   })},

第二次渲染-裁剪加填充

第二次渲染,把背景裁剪一个圆,并把图片填充进去。 :

异步绘制头像函数,接受远程头像URL作为参数,进行绘制操作。   const [err, res] = await uni.getImageInfo({ 我采用了云存储服务中的图片链接格式,具体为:prefix为cloud://,src字段则指向远程头像的URL。   })   if (err) {     throw err   }   const { path } = res   const img = canvas.createImage()   img.src = path 测量数据被应用于此处,设定了以下变量:x轴偏移量为120px,y轴偏移量同样为120px;圆的直径为190px,通过计算得到半径为95px;为了去除原有logo的纯色边缘,增加了2px的边框宽度;接下来定义了一个对象,用于描述裁剪圆的大小属性,其中x坐标为120px偏移加上半径。     y: offsetY + radius, 半径:半径数值增加边界宽度值   }   await new Promise((resolve, reject) => {     img.onload = () => {       ctx.save() 启动操作!将原有的标志图案彻底移除!执行绘制圆形命令,设置圆心坐标为circle.x和circle.y,半径为circle.radius,绘制从0度到180度的半圆,逆时针方向。       ctx.clip() 将我们所需的自定义图片,均匀地铺展开来,其中!使用ctx.drawImage()函数即可实现。         img, X轴偏移量减去边框宽度, 偏移量减去边框宽度。         circle.radius * 2,         circle.radius * 2       ) 执行完毕后,调用ctx对象的restore方法以恢复之前保存的画布状态。       resolve()     }     img.onerror = (event) => {       reject(event)     }   })},

经过上述几个步骤,我们便能轻松地完成图像处理环节,进而将中间预设的Logo替换为个性化的图像。

预览及下载到本地

异步获取tempFilePath,并调用getImage函数。 在执行uni.canvasToTempFilePath函数时,我们期待着得到两个结果:一个错误信息和一个响应对象,分别用const关键字声明的err和res变量来接收,这个过程是通过await关键字来异步等待的。     canvas   })   if (err) {     throw err   } 返回结果临时文件路径,执行预览操作,通过async函数preview传入源文件src。   if (src) {     uni.previewImage({       urls: [src]     }) 将图片资料存入相册中,通过异步操作实现,调用save函数并传入图片源路径。   try { 先进行授权操作,然后执行保存步骤,等待`authorize('scope.writePhotosAlbum')`函数的执行结果。 在执行uni.saveImageToPhotosAlbum()函数时,我们得到了两个结果,一个是错误信息(err),另一个是响应数据(res),整个过程通过await关键字进行异步等待。       filePath: src     })     if (err) {       throw err     } 此操作已顺利完成,系统提示“保存成功!”。   } catch (e) {     console.error(e)   }}

就这样,客户端生成自定义小程序码的整套解决方案就完成了

效果展示

自定义码

您可以通过微信搜索“程序员名片”,随后对名片进行维护,上传个人头像,并点击下方的“分享二维码”按钮,这样就可以提前查看效果了。

分享