$this->image_lib->watermark() 支持图片水印但不支持文字,要求水印图为带alpha通道的png、使用绝对路径且需预校验尺寸与权限,否则易致空白输出或报错。

$this->image_lib->watermark() 能加水印,但默认行为容易踩坑——它不自动缩放水印图,也不校验尺寸兼容性,直接调用常导致空白输出或报错。
水印图必须是 PNG 且带透明通道
GD2 对水印格式敏感:watermark() 内部使用 imagecopy() 或 imagecopymerge(),若水印是 JPG 或无 Alpha 通道的 PNG,透明区域会变黑块或完全覆盖原图。实操中建议:
- 用图像工具导出带透明背景的 PNG(非“白底+透明”伪透明)
- 避免用 GD 自己生成水印图再传入——
watermark()不接受资源句柄,只认磁盘路径 - 检查水印文件头:
file -i watermark.png应含png image data, 8-bit/color RGBA
watermark() 的位置参数实际生效逻辑
CI 的 position 参数(如 'topleft'、'center')不是像素精确定位,而是基于「水印图尺寸 vs 原图尺寸」做相对锚点计算。常见误解是以为设了 'bottomright' 就一定贴右下角,其实:
- 若水印宽 > 原图宽,
'bottomright'会把水印左上角对齐原图右下角,导致水印大部分被裁掉 -
'center'是让水印中心点对齐原图中心点,不是“居中铺满” - 真要像素级定位,得手动算偏移:用
getimagesize()先读原图和水印尺寸,再设'x_axis'和'y_axis'
文字水印?别用 watermark(),改用 imagestring() 手动叠加
$this->image_lib->watermark() 只支持图片水印,不支持文字。想打「©2026」或用户 ID,得绕过它:
- 先用
$this->image_lib->resize()或crop()处理完主图,保留资源句柄(需自己imagecreatefromxxx()加载) - 用 GD 原生函数:
imagestring()(位图字体)或imagettftext()(TTF 字体),注意后者需指定绝对路径到 .ttf 文件 - 最后
imagepng()写出,别再走 CI 的dynamic_output流程——它会清空资源
内存溢出和权限错误最常发生在哪一步
两个隐形雷区:
-
source_image和watermark_image路径必须是服务器可读的**绝对路径**(不是 URL),且 PHP 进程有读取权限;用APPPATH或FCPATH拼接比相对路径可靠 - 大图加水印时,GD2 默认吃内存:一张 4000×3000 的 JPG,加载后内存占用可能超 100MB;建议在
initialize()前加ini_set('memory_limit', '256M');,或先用resize()缩小原图再加水印
真正麻烦的不是调用函数,而是水印图尺寸、透明通道、路径权限这三者组合出的隐性失败——报错信息里往往只写 Unable to locate the source image,但实际是水印 PNG 缺 Alpha 通道或路径权限不对。











