解锁微信小程序码新玩法:自定义中间 Logo 全攻略

210 阅读3分钟

在 LINK PAY 收银系统小程序平台上,不少商家提出了一个共性需求:希望在店铺专属的小程序码 / 二维码中嵌入自己的店铺 Logo,而非默认显示的小程序头像。

图片

通常情况下,无论是通过微信小程序 MP 官方后台的小程序码生成工具,还是调用官方服务端 API 生成的小程序码,都不支持自定义 Logo,生成的二维码默认会使用小程序的头像(如下图所示)。

图片图片

临时解决方案:借助第三方工具实现部分需求

若仅针对单个店铺的个性化需求,可通过 “草料二维码” 工具的 “小程序参数码” 功能,生成指向店铺主页的小程序二维码,再利用该工具的 “二维码美化排版” 功能替换成店铺 Logo。不过,这种方法存在明显局限 —— 仅能生成二维码,无法生成小程序码,难以完全满足商家对小程序码的使用需求。

图片

通用解决方案:开发系统后台自动合成功能

正是看到了商家的这一普遍需求,我们意识到:若能在 LINK PAY 系统后台开发一项功能,让系统自动根据商家店铺的 Logo 生成带自定义 Logo 的小程序码,必将成为深受商家欢迎的实用功能。最终效果如何所示:

图片

由于微信官方服务端 API 生成的小程序码,其中间的 Logo 仅能调用小程序头像,无法直接替换,因此我们只能从 “后期处理已生成的小程序码图片” 入手。核心思路很简单:将商家店铺的 Logo 与生成好的小程序码进行图片合成叠加,用店铺 Logo 覆盖掉小程序码上默认的头像 Logo,从而得到带自定义 Logo 的小程序码。

然而,思路虽清晰,实际开发却充满细节挑战,仅调试就耗费了一整晚。关键难点在于:

需将商家上传的店铺 Logo 处理成圆形且背景为透明的 PNG 格式图片;

合成后的 Logo 背景色不能变成黑色或白色,必须保证视觉上 “毫无违和感”,达到 “无 PS 痕迹” 的自然效果。

针对上述需求与挑战,以下是实现该功能的核心代码:

/**
 * 生成自定义Logo的小程序码
 * @param string $wxCodeData 小程序码二进制数据
 * @param string $directory 小程序码保存路径
 * @param string $filename 小程序码文件名
 * @param string $logoPath 替换新的logo图路径
 * @return false|string
 * @author jiang
 */
public static function generateCodeWithLogo($wxCodeData, string $directory, string $filename, $logoPath)
{
    // 提前检查目录权限,避免后续处理后才发现问题
    $directory = rtrim($directory, '/');
    if (!is_dir($directory) && !mkdir($directory, 0755, true)) {
        return false;
    }
    if (!is_writable($directory)) {
        return false;
    }

    // 提前读取logo内容,减少文件操作
    $logoContent = @file_get_contents($logoPath);
    if ($logoContent === false) {
        return false;
    }

    try {
        // 创建小程序码图像资源并保留透明通道
        $wxCode = imagecreatefromstring($wxCodeData);
        if (!$wxCode) {
            return false;
        }
        imagesavealpha($wxCode, true);
        imagealphablending($wxCode, true);

        // 获取小程序码尺寸并计算Logo大小(只计算一次)
        $codeWidth = imagesx($wxCode);
        $codeHeight = imagesy($wxCode);
        $logoSize = (int)($codeWidth / 2.2); // 使用整数运算提高效率

        // 处理Logo为圆形(带透明背景)
        $logo = imagecreatefromstring($logoContent);
        $logo = rounded_corner($logo); // 确保此函数返回带透明通道的图像
        if (!$logo) {
            imagedestroy($wxCode); // 及时释放资源
            return false;
        }

        // 计算Logo位置(居中)
        $logoX = ($codeWidth - $logoSize) / 2;
        $logoY = ($codeHeight - $logoSize) / 2;
        $borderSize = 5;
        $borderedSize = $logoSize + $borderSize * 2;
        $borderedHalfSize = $borderedSize / 2;

        // 创建带边框的Logo画布(合并了原logoResized和border步骤)
        $borderedLogo = imagecreatetruecolor($borderedSize, $borderedSize);
        imagesavealpha($borderedLogo, true);
        $transparent = imagecolorallocatealpha($borderedLogo, 0, 0, 0, 127);
        imagefill($borderedLogo, 0, 0, $transparent);

        // 绘制白色圆形边框
        $white = imagecolorallocate($borderedLogo, 255, 255, 255);
        imagefilledellipse(
            $borderedLogo,
            $borderedHalfSize,
            $borderedHalfSize,
            $logoSize + $borderSize,
            $logoSize + $borderSize,
            $white
        );

        // 调整Logo大小并直接复制到带边框的画布(减少中间步骤)
        imagealphablending($borderedLogo, true);
        imagecopyresampled(
            $borderedLogo,
            $logo,
            $borderSize, $borderSize, 0, 0,
            $logoSize, $logoSize,
            imagesx($logo), imagesy($logo)
        );
        imagesavealpha($borderedLogo, true);

        // 释放不再需要的资源
        imagedestroy($logo);

        // 将带边框的Logo合成到小程序码
        imagealphablending($wxCode, true); // 允许透明叠加
        imagecopy(
            $wxCode,
            $borderedLogo,
            $logoX - $borderSize,
            $logoY - $borderSize,
            0, 0,
            $borderedSize,
            $borderedSize
        );

        // 释放边框Logo资源
        imagedestroy($borderedLogo);

        // 保存合成后的图片
        $savePath = $directory . '/' . $filename;
        $saveResult = imagepng($wxCode, $savePath);

        // 释放主图像资源
        imagedestroy($wxCode);

        return $saveResult ? $filename : false;

    } catch (Exception $e) {
        return false;
    }
}

  


  


好了,有需要的同学可以拿去参考,这个核心逻辑使用PHP GD库来实现的,PHP需要安装GD库扩展哦。

  


  
**END.**  


  


其他同学有更好的方案,或者优化建议,可以一起交流探讨哦~~~