PHP实现自定义中心图片的二维码生成
本文将详细讲解如何使用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步:调用流程整合
将上述步骤串联,主程序逻辑如下:
- 初始化
QRCode类获取二维码二进制数据。 - 将二进制数据保存为
qrcode_base.png。 - 接收用户提交的自定义图片URL(如
$surl)。 - 下载自定义图片并重命名。
- 调用
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图像处理与二维码合成的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













