必须用 imagecopymerge() 控制水印透明度;imagecopy() 无透明度参数,会覆盖 alpha 通道导致边缘发虚或背景失真。

用 imagecopy() 还是 imagecopymerge()?选错就透明度失控
直接结论:想控制水印透明度,必须用 imagecopymerge();用 imagecopy() 会硬叠加,PNG 水印的 alpha 通道完全失效,文字边缘发虚或背景色被吃掉。
关键区别在于:imagecopymerge() 第 8 个参数是合并透明度(0–100),而 imagecopy() 没有该参数,直接像素覆盖。哪怕你的水印图本身带 alpha,不用 imagecopymerge() 就等于白做。
- 源图和水印图都需用对应函数开启 alpha 支持:
imagealphablending($img, false)+imagesavealpha($img, true) - PNG 水印文件本身必须是 24 位真彩+alpha(不是索引色 PNG),否则
imagecreatefrompng()读出来 alpha 信息就丢了 - 如果水印是文字而非图片,改用
imagettftext(),它原生支持 alpha,但需确保字体文件路径正确且有读取权限
GD 库没启用或不支持 PNG?先检查 phpinfo() 里的这几项
常见报错如 Call to undefined function imagecreatefrompng() 或生成的图全黑/空白,大概率是 GD 缺功能。
运行 phpinfo() 后搜索以下三项,缺一不可:
立即学习“PHP免费学习笔记(深入)”;
-
gd.jpeg_ignore_warning→ 表示 JPEG 支持正常(顺带验证 GD 已加载) -
GD Version→ 必须是 >= “bundled (2.1.0 compatible)” 或系统库版本 -
FreeType Support和FreeType Linkage→ 如果要用文字水印,这个必须为 “enabled”
Ubuntu/Debian 下补装命令:sudo apt install php-gd;CentOS/RHEL:yum install php-gd 或 dnf install php-gd。装完记得重启 PHP-FPM 或 Apache。
水印位置计算总出错?别手算,用 getimagesize() 和 imagesx()/imagesy()
手动写死坐标(比如 10, 10)看似简单,实际在不同尺寸图上极易跑偏——水印可能被裁、压字、贴到画布外。
正确做法是动态算:
$src_size = getimagesize($src_path); $src_w = $src_size[0]; $src_h = $src_size[1]; <p>$watermark_w = imagesx($watermark_img); $watermark_h = imagesy($watermark_img);</p><p>// 右下角留 10px 边距 $dst_x = $src_w - $watermark_w - 10; $dst_y = $src_h - $watermark_h - 10;
注意:getimagesize() 返回的是原始文件宽高,imagesx() 是 GD 图像资源的实际像素宽——二者通常一致,但若图像被缩放或含 EXIF 方向信息,可能不等。稳妥起见,所有坐标计算统一用 imagesx()/imagesy()。
生成后图片变大、变糊、颜色失真?检查输出前的三步清理
不是代码逻辑错,而是 GD 默认压缩策略太激进。尤其对 PNG,不干预就会丢 alpha 或强制转为索引色。
- 输出 PNG 前务必加:
imagealphablending($dst_img, false)+imagesavealpha($dst_img, true) - 输出 JPEG 时,
imagejpeg($dst_img, null, 95)显式指定质量(默认是 75,肉眼可见模糊) - 别漏掉
imagedestroy()—— 多次调用不释放资源会导致内存暴涨,小图看不出,批量处理时 10 张图就可能 OOM
另外,imagecreatefromxxx() 系列函数读图失败会返回 false,但不会报错。务必用 if (!$src_img) die('无法加载原图'); 这类判断兜底,否则后面操作全静默失败。
最易被忽略的一点:水印图尺寸远大于原图时,imagecopymerge() 仍会强行复制,导致目标区域溢出、PHP 报 warning 甚至 crash。加一层尺寸校验再动手更稳。



















