imagecopymerge不支持PNG水印alpha通道,会导致透明背景变黑;须用imagecreatetruecolor创建真彩色画布,配合imagecolorallocatealpha填充透明底,再用imagecopy无损复制水印。

imagecopymerge 是 TP5 中最常用、也最容易出问题的水印函数,它不支持 PNG 水印的 alpha 通道保留——哪怕你用的是透明 PNG,叠加到 JPEG 上后背景会变黑灰。这不是你代码写错了,是 GD 库底层限制。
为什么 imagecopymerge 会让 PNG 水印变黑?
因为 imagecopymerge 只做简单像素混合,不处理 alpha 通道。当你把一个带透明背景的 PNG(比如 logo.png)用它贴到 JPEG 上时,GD 会把 PNG 的透明区域当成“黑色+0% alpha”,而 JPEG 本身不存 alpha,结果就是黑底。
- 只对真彩色图像(
imagecreatetruecolor创建的)才部分支持 alpha,但前提是两张图都得是 truecolor 且同色深 - 源图是 JPEG →
imagecreatefromjpeg返回的是调色板/真彩色混合模式,不是纯 truecolor - 水印是 PNG →
imagecreatefrompng默认开启 alpha,但一旦被imagecopymerge拉过去,alpha 就丢了
TP5 自定义函数必须手动重建透明上下文
不能直接 imagecopymerge($im, $watermark, ...)。得先用 imagecreatetruecolor 创建一块和水印尺寸一致的真彩色画布,再用 imagecolorallocatealpha 填充透明底,最后用 imagecopy 把水印“无损搬进去”——这一步才是保留透明的关键。
-
imagecolorallocatealpha($cut, 255, 255, 255, 127)中第四个参数是 alpha(0 完全不透明,127 完全透明),别写成 0 或 255 - 水印图必须是 PNG,且本身带 alpha 通道(用 Photoshop 或 GIMP 导出时勾选“透明度”)
- 调用
imagecopy时,目标画布($cut)和源水印($watermark)都得是 truecolor,否则imagecopy也会丢透明
位置控制别硬编码,用 ThinkPHP 的常量逻辑复用
TP5 内置的 \think\Image::WATER_SOUTHEAST 这类常量本质就是坐标计算规则。你在自定义函数里照着抄就行,不用另起一套:
- 右下角:
$x = $bgWidth - $logoWidth - 10; $y = $bgHight - $logoHight - 10; - 居中:
$x = ($bgWidth - $logoWidth) / 2; $y = ($bgHight - $logoHight) / 2; - 左上角:
$x = 10; $y = 10; - 千万别用循环平铺(如
for($x=0;...)),既卡又难调,TP5 场景基本不需要全屏水印
保存前记得销毁资源,否则内存泄漏
TP5 请求生命周期短,但图片资源不释放会导致 PHP 进程内存持续上涨,尤其在批量上传场景下容易触发 OOM。
- 每张图处理完必须调用
imagedestroy($im)和imagedestroy($watermark) - 中间画布
$cut也要imagedestroy($cut) - 如果函数里用了
imagecreatefromstring(file_get_contents(...)),就别再用imagecreatefromjpeg,避免重复加载同一张图
真正麻烦的从来不是“怎么加”,而是“怎么加完还看不出破绽”。PNG 水印的透明通道、JPEG 的色彩空间、GD 的 alpha 处理逻辑——三者稍有错位,黑边、白块、色差就全来了。写自定义函数时,宁可多两行创建 truecolor 画布,也不要省掉 imagecolorallocatealpha。

















