本文目录导读:

我来详细介绍使用PHP的GD库和Imagick扩展动态生成图像水印的方法。
使用GD库生成水印
图片水印
<?php
/**
* 使用GD库添加图片水印
* @param string $sourcePath 原图路径
* @param string $watermarkPath 水印图片路径
* @param string $outputPath 输出路径
* @param int $position 水印位置(1-9,类似九宫格)
* @param int $opacity 透明度(0-100)
*/
function addWatermarkWithGD($sourcePath, $watermarkPath, $outputPath, $position = 9, $opacity = 50) {
// 获取原图信息
$sourceInfo = getimagesize($sourcePath);
$sourceWidth = $sourceInfo[0];
$sourceHeight = $sourceInfo[1];
$sourceMime = $sourceInfo['mime'];
// 创建原图资源
switch ($sourceMime) {
case 'image/jpeg':
$sourceImg = imagecreatefromjpeg($sourcePath);
break;
case 'image/png':
$sourceImg = imagecreatefrompng($sourcePath);
break;
case 'image/gif':
$sourceImg = imagecreatefromgif($sourcePath);
break;
default:
return false;
}
// 获取水印图片信息
$watermarkInfo = getimagesize($watermarkPath);
$watermarkWidth = $watermarkInfo[0];
$watermarkHeight = $watermarkInfo[1];
// 创建水印图片资源
$watermarkImg = imagecreatefrompng($watermarkPath);
// 设置水印位置(边距20像素)
$margin = 20;
switch ($position) {
case 1: // 左上
$destX = $margin;
$destY = $margin;
break;
case 2: // 中上
$destX = ($sourceWidth - $watermarkWidth) / 2;
$destY = $margin;
break;
case 3: // 右上
$destX = $sourceWidth - $watermarkWidth - $margin;
$destY = $margin;
break;
case 4: // 左中
$destX = $margin;
$destY = ($sourceHeight - $watermarkHeight) / 2;
break;
case 5: // 居中
$destX = ($sourceWidth - $watermarkWidth) / 2;
$destY = ($sourceHeight - $watermarkHeight) / 2;
break;
case 6: // 右中
$destX = $sourceWidth - $watermarkWidth - $margin;
$destY = ($sourceHeight - $watermarkHeight) / 2;
break;
case 7: // 左下
$destX = $margin;
$destY = $sourceHeight - $watermarkHeight - $margin;
break;
case 8: // 中下
$destX = ($sourceWidth - $watermarkWidth) / 2;
$destY = $sourceHeight - $watermarkHeight - $margin;
break;
case 9: // 右下
$destX = $sourceWidth - $watermarkWidth - $margin;
$destY = $sourceHeight - $watermarkHeight - $margin;
break;
default:
$destX = $sourceWidth - $watermarkWidth - $margin;
$destY = $sourceHeight - $watermarkHeight - $margin;
}
// 应用透明度并合并图片
imagecopymerge($sourceImg, $watermarkImg, $destX, $destY, 0, 0,
$watermarkWidth, $watermarkHeight, $opacity);
// 保存图片
switch ($sourceMime) {
case 'image/jpeg':
imagejpeg($sourceImg, $outputPath, 90);
break;
case 'image/png':
imagepng($sourceImg, $outputPath, 9);
break;
case 'image/gif':
imagegif($sourceImg, $outputPath);
break;
}
// 释放内存
imagedestroy($sourceImg);
imagedestroy($watermarkImg);
return true;
}
// 使用示例
addWatermarkWithGD('source.jpg', 'watermark.png', 'output.jpg', 9, 50);
文字水印
<?php
/**
* 使用GD库添加文字水印
* @param string $sourcePath 原图路径
* @param string $outputPath 输出路径
* @param string $text 水印文字
* @param array $options 配置选项
*/
function addTextWatermarkWithGD($sourcePath, $outputPath, $text, $options = []) {
// 默认配置
$defaultOptions = [
'fontSize' => 20,
'fontColor' => [255, 255, 255],
'fontFile' => './arial.ttf', // 需要字体文件
'position' => 9,
'opacity' => 50,
'angle' => 0
];
$options = array_merge($defaultOptions, $options);
// 获取原图信息
$sourceInfo = getimagesize($sourcePath);
$sourceWidth = $sourceInfo[0];
$sourceHeight = $sourceInfo[1];
$sourceMime = $sourceInfo['mime'];
// 创建原图资源
switch ($sourceMime) {
case 'image/jpeg':
$sourceImg = imagecreatefromjpeg($sourcePath);
break;
case 'image/png':
$sourceImg = imagecreatefrompng($sourcePath);
break;
case 'image/gif':
$sourceImg = imagecreatefromgif($sourcePath);
break;
default:
return false;
}
// 计算文字尺寸
$bbox = imagettfbbox($options['fontSize'], $options['angle'],
$options['fontFile'], $text);
$textWidth = $bbox[2] - $bbox[0];
$textHeight = $bbox[1] - $bbox[7];
// 设置位置
$margin = 20;
switch ($options['position']) {
case 1: // 左上
$x = $margin;
$y = $margin + $textHeight;
break;
case 3: // 右上
$x = $sourceWidth - $textWidth - $margin;
$y = $margin + $textHeight;
break;
case 5: // 居中
$x = ($sourceWidth - $textWidth) / 2;
$y = ($sourceHeight + $textHeight) / 2;
break;
case 7: // 左下
$x = $margin;
$y = $sourceHeight - $margin;
break;
case 9: // 右下
$x = $sourceWidth - $textWidth - $margin;
$y = $sourceHeight - $margin;
break;
default:
$x = $sourceWidth - $textWidth - $margin;
$y = $sourceHeight - $margin;
}
// 创建文字颜色(带透明度)
$color = imagecolorallocatealpha($sourceImg,
$options['fontColor'][0],
$options['fontColor'][1],
$options['fontColor'][2],
(100 - $options['opacity']) / 100 * 127);
// 添加文字水印
imagettftext($sourceImg, $options['fontSize'], $options['angle'],
$x, $y, $color, $options['fontFile'], $text);
// 保存图片
switch ($sourceMime) {
case 'image/jpeg':
imagejpeg($sourceImg, $outputPath, 90);
break;
case 'image/png':
imagepng($sourceImg, $outputPath, 9);
break;
case 'image/gif':
imagegif($sourceImg, $outputPath);
break;
}
imagedestroy($sourceImg);
return true;
}
// 使用示例
addTextWatermarkWithGD('source.jpg', 'output.jpg', '© 2024 My Website', [
'fontSize' => 24,
'fontColor' => [255, 255, 255],
'fontFile' => './fonts/arial.ttf',
'position' => 9,
'opacity' => 70,
'angle' => 0
]);
使用Imagick扩展生成水印
图片水印
<?php
/**
* 使用Imagick添加图片水印
* @param string $sourcePath 原图路径
* @param string $watermarkPath 水印图片路径
* @param string $outputPath 输出路径
* @param int $position 水印位置
* @param int $opacity 透明度(0-100)
*/
function addWatermarkWithImagick($sourcePath, $watermarkPath, $outputPath,
$position = 9, $opacity = 50) {
try {
// 创建Imagick对象
$image = new Imagick($sourcePath);
$watermark = new Imagick($watermarkPath);
// 获取尺寸
$imageWidth = $image->getImageWidth();
$imageHeight = $image->getImageHeight();
$watermarkWidth = $watermark->getImageWidth();
$watermarkHeight = $watermark->getImageHeight();
// 设置透明度
$watermark->setImageOpacity($opacity / 100);
// 计算位置
$margin = 20;
switch ($position) {
case 1: // 左上
$x = $margin;
$y = $margin;
break;
case 3: // 右上
$x = $imageWidth - $watermarkWidth - $margin;
$y = $margin;
break;
case 5: // 居中
$x = ($imageWidth - $watermarkWidth) / 2;
$y = ($imageHeight - $watermarkHeight) / 2;
break;
case 7: // 左下
$x = $margin;
$y = $imageHeight - $watermarkHeight - $margin;
break;
case 9: // 右下
$x = $imageWidth - $watermarkWidth - $margin;
$y = $imageHeight - $watermarkHeight - $margin;
break;
default:
$x = $imageWidth - $watermarkWidth - $margin;
$y = $imageHeight - $watermarkHeight - $margin;
}
// 合并图片
$image->compositeImage($watermark, Imagick::COMPOSITE_OVER, $x, $y);
// 保存图片
$image->writeImage($outputPath);
// 清理内存
$image->clear();
$watermark->clear();
return true;
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
return false;
}
}
// 使用示例
addWatermarkWithImagick('source.jpg', 'watermark.png', 'output.jpg', 9, 50);
文字水印
<?php
/**
* 使用Imagick添加文字水印
* @param string $sourcePath 原图路径
* @param string $outputPath 输出路径
* @param string $text 水印文字
* @param array $options 配置选项
*/
function addTextWatermarkWithImagick($sourcePath, $outputPath, $text, $options = []) {
// 默认配置
$defaultOptions = [
'fontSize' => 24,
'fontColor' => 'white',
'backgroundColor' => 'transparent',
'fontFile' => './arial.ttf',
'position' => 9,
'opacity' => 50,
'angle' => 0,
'gravity' => Imagick::GRAVITY_SOUTHEAST
];
$options = array_merge($defaultOptions, $options);
try {
// 创建原图对象
$image = new Imagick($sourcePath);
// 创建文字水印对象
$draw = new ImagickDraw();
$draw->setFont($options['fontFile']);
$draw->setFontSize($options['fontSize']);
$draw->setFillColor(new ImagickPixel($options['fontColor']));
$draw->setTextAlignment(Imagick::ALIGN_CENTER);
// 获取文字尺寸
$metrics = $image->queryFontMetrics($draw, $text);
$textWidth = $metrics['textWidth'];
$textHeight = $metrics['textHeight'];
// 创建水印图层
$watermark = new Imagick();
$watermark->newImage($textWidth + 40, $textHeight + 40,
new ImagickPixel($options['backgroundColor']));
$watermark->setImageFormat('png');
// 设置透明度
$watermark->setImageOpacity($options['opacity'] / 100);
// 绘制文字
$watermark->annotateImage($draw, 20, $textHeight + 20,
$options['angle'], $text);
// 设置水印位置
$imageWidth = $image->getImageWidth();
$imageHeight = $image->getImageHeight();
$watermarkWidth = $watermark->getImageWidth();
$watermarkHeight = $watermark->getImageHeight();
$margin = 20;
switch ($options['position']) {
case 1: // 左上
$x = $margin;
$y = $margin;
break;
case 3: // 右上
$x = $imageWidth - $watermarkWidth - $margin;
$y = $margin;
break;
case 5: // 居中
$x = ($imageWidth - $watermarkWidth) / 2;
$y = ($imageHeight - $watermarkHeight) / 2;
break;
case 7: // 左下
$x = $margin;
$y = $imageHeight - $watermarkHeight - $margin;
break;
case 9: // 右下
$x = $imageWidth - $watermarkWidth - $margin;
$y = $imageHeight - $watermarkHeight - $margin;
break;
default:
$x = $imageWidth - $watermarkWidth - $margin;
$y = $imageHeight - $watermarkHeight - $margin;
}
// 合并图片
$image->compositeImage($watermark, Imagick::COMPOSITE_OVER, $x, $y);
// 保存图片
$image->writeImage($outputPath);
// 清理内存
$image->clear();
$watermark->clear();
return true;
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
return false;
}
}
// 使用示例
addTextWatermarkWithImagick('source.jpg', 'output.jpg', '© 2024 My Website', [
'fontSize' => 30,
'fontColor' => 'white',
'fontFile' => './fonts/arial.ttf',
'position' => 9,
'opacity' => 60,
'angle' => -30 // 旋转角度
]);
批量处理水印
<?php
/**
* 批量添加水印
* @param string $directory 图片目录
* @param string $watermarkPath 水印路径
* @param string $outputDirectory 输出目录
* @param string $method 方法(gd或imagick)
*/
function batchAddWatermark($directory, $watermarkPath, $outputDirectory, $method = 'gd') {
// 确保输出目录存在
if (!file_exists($outputDirectory)) {
mkdir($outputDirectory, 0777, true);
}
// 获取所有图片文件
$files = glob($directory . '/*.{jpg,jpeg,png,gif}', GLOB_BRACE);
foreach ($files as $file) {
$filename = basename($file);
$outputPath = $outputDirectory . '/' . $filename;
if ($method == 'gd') {
addWatermarkWithGD($file, $watermarkPath, $outputPath, 9, 50);
} else {
addWatermarkWithImagick($file, $watermarkPath, $outputPath, 9, 50);
}
echo "Processed: $filename\n";
}
}
// 使用示例
batchAddWatermark('images/', 'watermark.png', 'watermarked_images/', 'gd');
性能对比与选择建议
GD库:
- 优点:PHP内置,无需额外安装
- 缺点:功能相对简单,处理大图片时性能较差
- 适用场景:简单水印需求,对性能要求不高
Imagick扩展:
- 优点:功能强大,支持更多图像格式,性能更好
- 缺点:需要安装扩展,资源消耗较大
- 适用场景:复杂水印需求,大批量处理
选择建议:如果只是简单的图片水印,使用GD库即可;如果有复杂的文字效果或需要处理高分辨率图片,建议使用Imagick。
注意事项
- 字体文件:使用文字水印时需要确保字体文件路径正确
- 权限问题:确保目录有写入权限
- 内存限制:处理大图片时可能需要调整PHP内存限制
- 错误处理:添加适当的错误处理和日志记录
- 缓存机制:对于频繁访问的图片,建议添加缓存机制