imagecopy()是硬覆盖,imagecopymerge()支持透明度混合;PNG水印配JPG原图需用后者或手动处理alpha;文字水印须用imagettftext()并注意字体路径、编码、坐标等细节。

PHP 使用 imagecopy() 或 imagecopymerge() 添加水印的实质区别
加水印不是简单“贴一张图”,核心在于图层叠加方式。用 imagecopy() 是硬覆盖(不透明粘贴),而 imagecopymerge() 支持透明度混合(第二个参数传 50 表示水印半透明)。若水印 PNG 带 alpha 通道,但目标图是 JPEG,直接 imagecopy() 会丢失透明背景,变成黑底;此时必须先用 imagealphablending($dst, true) 和 imagesavealpha($dst, true) 控制合成行为。
- 对 JPG 原图 + PNG 水印:优先用
imagecopymerge(),避免手动处理 alpha - 需要精确控制文字水印位置或旋转角度:改用
imagettftext(),而非图像叠加 - 水印图尺寸远大于原图时,
imagecopyresized()可先缩放再贴,否则会截断
文字水印必须设置字体路径和字符编码
imagettftext() 不认相对路径,也不自动识别系统字体。传入的字体文件路径必须是绝对路径(如 /var/www/font/yahei.ttf),且 PHP 进程要有读取权限。中文文字默认按 ISO-8859-1 编码解析,直接传 UTF-8 字符串会乱码或报错 Warning: imagettftext(): Could not read font —— 必须用 mb_convert_encoding($text, 'ISO-8859-1', 'UTF-8') 转换。
- 测试前先用
file_exists($font_path)和is_readable($font_path)校验字体文件 - 字号单位是像素,不是 pt;太小(如 6)在高清图上几乎不可见
- 坐标 (x, y) 是文字基线左下角,不是左上角,y 值需预留行高余量
GD 库未启用或不支持 PNG/JPEG 会导致致命错误
运行时报 Call to undefined function imagecreatefromjpeg(),说明 GD 扩展没开,或编译时没带 JPEG/PNG 支持。Ubuntu 下装 php-gd 包后还需确认 gd.jpeg_ignore_warning 配置项为 On(否则损坏的 JPG 会中断脚本);Windows 下检查 php.ini 是否启用了 extension=gd,并确认 libpng.dll、libjpeg.dll 在系统 PATH 中。
- 用
extension_loaded('gd')和gd_info()提前检测,别等执行到imagecreatefrompng()才崩 - 部分共享主机禁用
getimagesize(),可用finfo_open(FILEINFO_MIME_TYPE)替代判断 MIME 类型 - 大图(>5MB)加水印易触发内存超限,加
ini_set('memory_limit', '256M')并用imagedestroy()及时释放资源
透明 PNG 水印在白色背景图上“消失”的原因
不是代码错了,是视觉欺骗:当水印 PNG 的 alpha 通道值全为 0(完全透明),或水印内容本身是白色(#FFFFFF)又叠在白色背景 JPG 上,人眼看不到。调试时临时把目标图背景改成深色(如用 imagefilledrectangle($dst, 0, 0, $dst_w, $dst_h, 0x000000) 填黑),就能立刻验证水印是否真的被绘制出来。
立即学习“PHP免费学习笔记(深入)”;
- 用
imagecolorallocatealpha($dst, 255, 255, 255, 127)创建半透明白色,比纯白更安全 - 水印位置建议避开右下角(常被裁剪),改用“居中偏右下 5%”这类动态计算:
$x = $dst_w * 0.95 - $water_w - 生产环境务必关闭
display_errors,用error_log()记录水印失败的具体步骤(比如哪一步imagecreatefromxxx()返回 false)











