PHP实现自定义中心图片的二维码生成

唐可
唐可
发布时间:2026-10-13 | 5人浏览过
原创

本文将详细讲解如何使用PHP语言,通过内置的GD图像处理库,将任意自定义图片居中嵌入到生成的二维码中。该方法利用 imagecopymerge 等函数进行图层混合,解决了直接覆盖导致二维码无法扫描的问题,同时包含了图片下载、尺寸适配及透明度控制的完整实现逻辑。

准备条件与原理说明

要在PHP环境中生成带有自定义中心图片的二维码,主要依赖以下两个核心环节:一是获取基础二维码数据;二是使用GD库对图像进行图层叠加。为了保证二维码的可扫描性,中心图片的面积通常不应超过整个二维码面积的30%,且需保持一定的对比度。

本方案采用PHP原生的 curl 扩展发起HTTP请求获取二维码底图,再利用 gd 模块提供的图像操作函数进行拼接,无需安装第三方图形类库即可完成开发。

第一阶段:获取二维码底图

第1步:编写二维码生成类

目的是创建一个封装好的类,通过API接口获取纯文本内容的二维码二进制流。虽然现代开发更多推荐使用本地生成的库(如Endroid QrCode),但理解底层API调用有助于掌握数据流转。以下代码展示了如何通过cURL向图表API发送请求:

class QRCode {
    public $w;
    public $h;
    public $s;

    function __construct($w1, $h1, $s1) {
        $this->w = $w1;
        $this->h = $h1;
        $this->s = $s1;
    }

    function qrcode() {
        $post_data = array(
            'cht' => 'qr',
            'chs' => $this->w."x".$this->h,
            'chl' => $this->s,
            'choe' => "UTF-8"
        );
        $url = "http://chart.apis.google.com/chart";
        $data_Array = array();
        foreach ($post_data as $key => $value) {
            $data_Array[] = $key.'='.$value;
        }
        $data = implode("&", $data_Array);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }
}

调用示例:$qr = new QRCode(300, 300, "https://example.com"); $qrData = $qr->qrcode();

第2步:保存二维码到临时文件

获取到的二进制数据需要写入文件系统,以便后续使用GD库读取。定义一个通用的图片下载函数 GrabImage 来处理这一过程:

function GrabImage($url, $filename = "") {
    if ($url == "") return false;
    if ($filename == "") {
        $ext = strrchr($url, ".");
        if ($ext != ".gif" && $ext != ".jpg" && $ext != ".png") return false;
        $filename = date("dMYHis") . $ext;
    }
    ob_start();
    readfile($url); // 若从API获取二进制流,此处应改为 fread(curl_getinfo) 或 file_put_contents
    $img = ob_get_contents();
    ob_end_clean();
    // 注意:上述readfile方式适用于直接URL获取,针对API返回的二进制流建议直接使用 file_put_contents($filename, $qrData);
    $fp2 = @fopen($filename, "w"); // 修改为 w 模式以重写
    fwrite($fp2, $img);
    fclose($fp2);
    return $filename;
}

提示:在实际合并逻辑中,如果上一步已经通过 file_put_contents 保存了二维码,这里可直接传入该路径。

第二阶段:图像处理与合成

第3步:获取图像信息并适配尺寸

在将自定义图片放入二维码前,必须确保水印图片尺寸合适。过大的图片会破坏二维码结构,过小则效果不佳。我们首先提取原图和中心图片的尺寸:

function getImageInfo($img) {
    $imageInfo = getimagesize($img);
    if ($imageInfo !== false) {
        $imageType = strtolower(substr(image_type_to_extension($imageInfo[2]), 1));
        $imageSize = filesize($img);
        $info = array(
            "width" => $imageInfo[0],
            "height" => $imageInfo[1],
            "type" => $imageType,
            "size" => $imageSize,
            "mime" => $imageInfo['mime']
        );
        return $info;
    } else {
        return false;
    }
}

接着编写缩放函数 thumb,计算缩放比例。若中心图片过大,将其缩小至二维码宽度的四分之一左右通常是安全范围:

function thumb($image, $thumbname, $type='', $maxWidth=200, $maxHeight=50, $interlace=true) {
    $info = getImageInfo($image);
    if ($info !== false) {
        $srcWidth = $info['width'];
        $srcHeight = $info['height'];
        $type = empty($type) ? $info['type'] : $type;
        $type = strtolower($type);
        
        // 简单的自适应缩放逻辑
        $scale = min($maxWidth / $srcWidth, $maxHeight / $srcHeight);
        if ($scale >= 1) {
            $width = $srcWidth;
            $height = $srcHeight;
        } else {
            $width = (int) ($srcWidth * $scale);
            $height = (int) ($srcHeight * $scale);
        }

        // 创建图像资源
        $createFun = 'imageCreateFrom' . ($type == 'jpg' ? 'jpeg' : $type);
        $srcImg = $createFun($image);
        
        $thumbImg = imagecreatetruecolor($width, $height);
        
        // 重采样复制图片
        imagecopyresampled($thumbImg, $srcImg, 0, 0, 0, 0, $width, $height, $srcWidth, $srcHeight);
        imagedestroy($srcImg);
        
        // 输出缩略图
        $imageFun = 'image' . ($type == 'jpg' ? 'jpeg' : $type);
        $imageFun($thumbImg, $thumbname);
        imagedestroy($thumbImg);
        return $thumbname;
    }
    return false;
}

第4步:执行图像混合(核心步骤)

这是实现“中间带自定义图片”的关键。使用 imagecopymerge 将缩放后的中心图片“盖”在二维码中间。为了保持二维码边缘的识别性,我们需要精确计算坐标:

function water($source, $thumb, $savename="", $alpha=100) {
    // 检查文件是否存在
    if (!file_exists($source) || !file_exists($thumb)) return false;
    
    // 获取源图片(二维码)和水印图片(中心图)信息
    $sInfo = getImageInfo($source);
    
    // 对中心图进行二次适配,使其更适合放置在二维码中央
    // 这里假设将水印缩放到源图尺寸的 1/4 左右作为最大尝试,实际可根据需求调整
    $water = thumb($thumb, "wy_tmp.jpg", $sInfo['type'], $sInfo["width"]/4, $sInfo["height"]/4);
    $wInfo = getImageInfo($water);
    
    // 如果中心图比二维码还大,则不处理
    if ($sInfo["width"] < $wInfo["width"] || $sInfo['height'] < $wInfo['height']) return false;
    
    // 建立图像资源
    $sCreateFun = "imagecreatefrom" . $sInfo['type'];
    $sImage = $sCreateFun($source);
    $wCreateFun = "imagecreatefrom" . $wInfo['type'];
    $wImage = $wCreateFun($water);
    
    // 设定图像的混色模式
    imagealphablending($wImage, true);
    
    // 计算居中位置
    $posY = ($sInfo["height"] - $wInfo["height"]) / 2;
    $posX = ($sInfo["width"] - $wInfo["width"]) / 2;
    
    // 关键函数:将水印图片覆盖到源图上,alpha参数控制透明度
    // 对于黑白二维码,通常建议使用完全不透明或高对比度颜色背景的图片
    imagecopymerge($sImage, $wImage, $posX, $posY, 0, 0, $wInfo['width'], $wInfo['height'], $alpha);
    
    // 输出图像
    $ImageFun = 'Image' . $sInfo['type'];
    if (!$savename) {
        $savename = $source;
    }
    $ImageFun($sImage, $savename);
    
    imagedestroy($sImage);
    imagedestroy($wImage);
    
    // 清理临时文件
    @unlink($water);
}

第三阶段:整合运行与前端入口

第5步:调用流程整合

将上述步骤串联,主程序逻辑如下:

  1. 初始化 QRCode 类获取二维码二进制数据。
  2. 将二进制数据保存为 qrcode_base.png。
  3. 接收用户提交的自定义图片URL(如 $surl)。
  4. 下载自定义图片并重命名。
  5. 调用 water() 函数,参数为:源码路径、中心图路径、输出路径。

第6步:HTML交互界面

构建一个简单的表单供用户输入内容、选择图片地址并触发后端生成脚本。由于涉及服务器端图像处理和文件存储,前端仅作入口展示:

<html>
<head>
<title>中间可以自己定义图片的二维码生成器</title>
</head>
<body style="margin:0px; padding:0px; font-family:Arial, sans-serif; font-size:12px;">
<form action="generate.php" method="post">
<div style="width:500px; height:200px; background-color:#f0f0f0; margin:auto; border-width:1px; border-color:#ccc; padding:20px;">
<h1 style="margin:0px 0px 20px 0px; font-size:16px; text-align:center;">自定义中心图片二维码生成器</h1>
<table width="100%" border="0">
<tr>
<td width="30%" align="right">二维码内容:</td>
<td><input type="text" name="content" value="" style="width:90%;"></td>
</tr>
<tr>
<td align="right">中心图片URL:</td>
<td><input type="text" name="url" value="" style="width:90%;" placeholder="例如: http://example.com/logo.png"></td>
</tr>
<tr>
<td height="40" colspan="2" align="center">
<input type="submit" name="Submit" value="生成二维码">
</td>
</tr>
</table>
</div>
</body>
</html>

完成判断与排错指南

成功标志: 运行脚本后,在指定目录下能看到生成的最终图片文件。使用手机扫描二维码APP扫描该图片,若能正确跳转或显示预设内容,且中间图片清晰可见,即表示成功。

常见问题排查: 1. 二维码无法扫描:通常是因为中心图片过大,覆盖了过多的纠错码区域。解决方案是减小 water 函数中的缩放比例,或在图片四周增加白色/浅色边框以增强对比度缓冲。

2. 图片模糊:确保在 thumb 函数中使用了 imagecopyresampled 而非 imagecopyresized,前者支持更好的抗锯齿重采样。

3. 透明色干扰:如果中心图片是PNG透明格式,直接叠加可能导致黑色二维码点变成杂色。建议在生成中心图缩略图时,为其添加一个不透明的底色(如白色),或者在混合时使用 imagecopy 配合遮罩处理。

以上就是利用PHP制作中间带自定义图片二维码的详细内容,更多关于PHP图像处理与二维码合成的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表