本文目录导读:

在PHP中实现图片水印添加,主要使用 GD库 或 Imagick 扩展,以下是两种主流方法的详细实现方案:
使用GD库(最常用,无需额外安装)
文字水印
<?php
function addTextWatermark($sourcePath, $savePath, $text = 'Watermark') {
// 获取原图信息
list($width, $height, $type) = getimagesize($sourcePath);
// 根据图片类型创建资源
switch ($type) {
case IMAGETYPE_JPEG:
$image = imagecreatefromjpeg($sourcePath);
break;
case IMAGETYPE_PNG:
$image = imagecreatefrompng($sourcePath);
break;
case IMAGETYPE_GIF:
$image = imagecreatefromgif($sourcePath);
break;
default:
return false;
}
// 设置水印颜色(白色半透明)
$watermarkColor = imagecolorallocatealpha($image, 255, 255, 255, 50);
// 设置字体文件路径
$fontFile = './font/arial.ttf'; // 需要实际存在的字体文件
// 文字大小
$fontSize = 20;
// 计算文字位置(右下角)
$textBox = imagettfbbox($fontSize, 0, $fontFile, $text);
$textWidth = $textBox[2] - $textBox[0];
$textHeight = $textBox[1] - $textBox[7];
$x = $width - $textWidth - 20;
$y = $height - $textHeight - 20;
// 添加水印
imagettftext($image, $fontSize, 0, $x, $y, $watermarkColor, $fontFile, $text);
// 保存图片
switch ($type) {
case IMAGETYPE_JPEG:
imagejpeg($image, $savePath, 90);
break;
case IMAGETYPE_PNG:
imagepng($image, $savePath);
break;
case IMAGETYPE_GIF:
imagegif($image, $savePath);
break;
}
// 释放内存
imagedestroy($image);
return true;
}
// 使用示例
addTextWatermark('original.jpg', 'watermarked.jpg', '© 2024 My Site');
?>
图片水印(添加Logo)
<?php
function addImageWatermark($sourcePath, $watermarkPath, $savePath, $position = 'bottom-right') {
// 创建原图资源
list($srcWidth, $srcHeight, $srcType) = getimagesize($sourcePath);
switch ($srcType) {
case IMAGETYPE_JPEG:
$mainImg = imagecreatefromjpeg($sourcePath);
break;
case IMAGETYPE_PNG:
$mainImg = imagecreatefrompng($sourcePath);
break;
case IMAGETYPE_GIF:
$mainImg = imagecreatefromgif($sourcePath);
break;
default:
return false;
}
// 创建水印资源
list($wmWidth, $wmHeight, $wmType) = getimagesize($watermarkPath);
switch ($wmType) {
case IMAGETYPE_JPEG:
$watermark = imagecreatefromjpeg($watermarkPath);
break;
case IMAGETYPE_PNG:
$watermark = imagecreatefrompng($watermarkPath);
break;
case IMAGETYPE_GIF:
$watermark = imagecreatefromgif($watermarkPath);
break;
default:
return false;
}
// 计算位置
$padding = 10;
switch ($position) {
case 'top-left':
$x = $padding;
$y = $padding;
break;
case 'top-right':
$x = $srcWidth - $wmWidth - $padding;
$y = $padding;
break;
case 'bottom-left':
$x = $padding;
$y = $srcHeight - $wmHeight - $padding;
break;
case 'bottom-right':
default:
$x = $srcWidth - $wmWidth - $padding;
$y = $srcHeight - $wmHeight - $padding;
break;
}
// 保持PNG透明度
imagealphablending($mainImg, true);
imagesavealpha($mainImg, true);
// 合并图片
imagecopy($mainImg, $watermark, $x, $y, 0, 0, $wmWidth, $wmHeight);
// 保存
switch ($srcType) {
case IMAGETYPE_JPEG:
imagejpeg($mainImg, $savePath, 90);
break;
case IMAGETYPE_PNG:
imagepng($mainImg, $savePath);
break;
case IMAGETYPE_GIF:
imagegif($mainImg, $savePath);
break;
}
imagedestroy($mainImg);
imagedestroy($watermark);
return true;
}
// 使用示例
addImageWatermark('original.jpg', 'logo.png', 'watermarked.jpg', 'bottom-right');
?>
使用Imagick扩展(功能更强大,支持更多格式)
<?php
function addImagickWatermark($sourcePath, $savePath, $type = 'text', $content = 'Watermark') {
$image = new Imagick($sourcePath);
if ($type === 'text') {
// 文字水印
$draw = new ImagickDraw();
$draw->setFillColor(new ImagickPixel('white'));
$draw->setFontSize(30);
$draw->setOpacity(0.5);
$image->annotateImage($draw, 10, $image->getImageHeight() - 30, 0, $content);
} else {
// 图片水印
$watermark = new Imagick($content);
// 设置水印大小(可选)
$watermark->scaleImage(100, 0); // 宽度100px,高度自动
// 设置透明度
$watermark->evaluateImage(Imagick::EVALUATE_MULTIPLY, 0.5, Imagick::CHANNEL_ALPHA);
// 计算位置
$x = $image->getImageWidth() - $watermark->getImageWidth() - 10;
$y = $image->getImageHeight() - $watermark->getImageHeight() - 10;
// 合并图片
$image->compositeImage($watermark, Imagick::COMPOSITE_OVER, $x, $y);
$watermark->destroy();
}
$image->writeImage($savePath);
$image->destroy();
return true;
}
// 使用示例
addImagickWatermark('original.jpg', 'watermarked.jpg', 'text', '© 2024');
// 或者
addImagickWatermark('original.jpg', 'watermarked.jpg', 'image', 'logo.png');
?>
完整的水印类封装
<?php
class Watermark {
private $sourcePath;
private $savePath;
private $type; // gd or imagick
public function __construct($sourcePath, $savePath = null) {
$this->sourcePath = $sourcePath;
$this->savePath = $savePath ?: $sourcePath;
$this->type = extension_loaded('imagick') ? 'imagick' : 'gd';
}
public function addText($text, $options = []) {
$defaults = [
'fontSize' => 20,
'color' => 'white',
'opacity' => 50,
'position' => 'bottom-right',
'fontFile' => './font/arial.ttf'
];
$options = array_merge($defaults, $options);
if ($this->type === 'imagick') {
return $this->addTextImagick($text, $options);
} else {
return $this->addTextGD($text, $options);
}
}
public function addImage($watermarkPath, $options = []) {
$defaults = [
'position' => 'bottom-right',
'opacity' => 80,
'scale' => 0.3 // 水印缩放比例
];
$options = array_merge($defaults, $options);
if ($this->type === 'imagick') {
return $this->addImageImagick($watermarkPath, $options);
} else {
return $this->addImageGD($watermarkPath, $options);
}
}
// 私有方法实现细节...
}
?>
配置检查
<?php
// 检查GD库是否可用
if (function_exists('gd_info')) {
echo "GD库已安装\n";
print_r(gd_info());
}
// 检查Imagick是否可用
if (class_exists('Imagick')) {
echo "Imagick已安装\n";
}
?>
常见问题与优化建议
注意事项:
- 字体文件:使用imagettftext()时需要提供TrueType字体文件路径
- 透明度:PNG水印需要保留透明度信息
- 性能优化:
- 使用缓存机制避免重复处理
- 对于大图片考虑使用缩略图添加水印
- 使用队列系统处理批量水印
最佳实践:
// 异步处理水印
class WatermarkJob {
public function handle($imagePath) {
// 使用队列处理大量图片
$watermark = new Watermark($imagePath);
$watermark->addText('© 2024');
}
}
// 缓存水印处理结果
function getWatermarkedImage($sourcePath) {
$cachePath = './cache/' . md5($sourcePath) . '.jpg';
if (file_exists($cachePath)) {
return $cachePath; // 返回缓存
}
// 生成水印
$watermark = new Watermark($sourcePath, $cachePath);
$watermark->addText('© 2024');
return $cachePath;
}
推荐优先使用 GD库,因为它是PHP内置的,无需额外安装,如果项目需要处理大量图片或特殊格式,可以考虑使用 Imagick。