<think>我们使用GD库内置字体(而不是TrueType字体)来添加文本水印。GD库内置字体是1到5的整数,分别代表不同大小的字体。这些字体是固定大小的,不支持自定义大小,但处理速度快,不需要外部字体文件。
内置字体的使用函数:
- 获取文本宽度的函数:`imagefontwidth($font)`
- 获取文本高度的函数:`imagefontheight($font)`
- 写入文本的函数:`imagestring($image, $font, $x, $y, $string, $color)`
由于内置字体不支持自定义大小,所以我们需要根据所选字体号计算水印文本的宽度和高度。
我们仍然支持8个位置:top-left, top-center, top-right, middle-left, center, middle-right, bottom-left, bottom-center, bottom-right。
实现步骤:
1. 加载原始图片(支持JPEG和PNG)。
2. 根据选定的内置字体号(1-5)计算水印文本的宽度和高度。
3. 根据指定的位置计算水印的坐标(考虑边距)。
4. 使用`imagestring`函数将水印文本绘制到图片上。
5. 保存图片。
注意:内置字体不支持透明度,但我们可以通过调整文本颜色来模拟半透明效果(例如使用浅灰色)。但是,`imagestring`函数不支持透明度,所以如果需要半透明效果,我们可以使用其他方法(例如先创建一个带透明度的颜色,然后使用`imagestring`绘制,但内置字体绘制函数不支持透明度)。因此,我们这里不处理透明度,如果用户需要透明度,建议使用TrueType字体。
但是,根据要求,我们使用内置字体,所以只提供不透明的水印。用户可以通过设置颜色为浅色(如浅灰色)来降低水印的突兀感。
代码实现:
我们将创建一个函数,参数包括:
- $sourcePath: 源图片路径
- $outputPath: 输出图片路径
- $watermarkText: 水印文本
- $position: 位置,默认为'center'
- $font: 内置字体号(1-5),默认为5(较大字体)
- $color: 文本颜色,数组形式[R,G,B],默认为[255,255,255](白色)
由于内置字体不支持改变大小,所以没有字体大小参数。
完整代码:
```php
<?php
/**
* 使用GD库内置字体为图片添加文本水印
* @param string $sourcePath 原始图片路径
* @param string $outputPath 输出图片路径
* @param string $watermarkText 水印文本
* @param string $position 水印位置(默认'center')
* @param int $font 内置字体号(1-5,默认5)
* @param array $color 文本颜色,如[255,255,255]表示白色
* @return bool 成功返回true,失败返回false
*/
function addWatermarkWithBuiltInFont($sourcePath, $outputPath, $watermarkText, $position = 'center', $font = 5, $color = [255, 255, 255]) {
try {
// 验证字体号
if ($font < 1 || $font > 5) {
throw new Exception("字体号必须在1到5之间");
}
// 步骤1: 加载原始图片
$sourceInfo = getimagesize($sourcePath);
if (!$sourceInfo) {
throw new Exception("无法加载原始图片: $sourcePath");
}
$mimeType = $sourceInfo['mime'];
switch ($mimeType) {
case 'image/jpeg':
$sourceImage = imagecreatefromjpeg($sourcePath);
break;
case 'image/png':
$sourceImage = imagecreatefrompng($sourcePath);
break;
default:
throw new Exception("不支持的图片格式: $mimeType");
}
$sourceWidth = imagesx($sourceImage);
$sourceHeight = imagesy($sourceImage);
// 步骤2: 计算水印文本尺寸
$textWidth = imagefontwidth($font) * strlen($watermarkText);
$textHeight = imagefontheight($font);
// 步骤3: 计算水印位置(8个位置,加上边距10像素)
$positions = [
'top-left' => ['x' => 10, 'y' => 10],
'top-center' => ['x' => ($sourceWidth - $textWidth) / 2, 'y' => 10],
'top-right' => ['x' => $sourceWidth - $textWidth - 10, 'y' => 10],
'middle-left' => ['x' => 10, 'y' => ($sourceHeight - $textHeight) / 2],
'center' => ['x' => ($sourceWidth - $textWidth) / 2, 'y' => ($sourceHeight - $textHeight) / 2],
'middle-right' => ['x' => $sourceWidth - $textWidth - 10, 'y' => ($sourceHeight - $textHeight) / 2],
'bottom-left' => ['x' => 10, 'y' => $sourceHeight - $textHeight - 10],
'bottom-center' => ['x' => ($sourceWidth - $textWidth) / 2, 'y' => $sourceHeight - $textHeight - 10],
'bottom-right' => ['x' => $sourceWidth - $textWidth - 10, 'y' => $sourceHeight - $textHeight - 10]
];
if (!isset($positions[$position])) {
throw new Exception("无效的水印位置: $position。支持: " . implode(', ', array_keys($positions)));
}
$pos = $positions[$position];
$x = max(0, $pos['x']); // 确保坐标不超出边界
$y = max(0, $pos['y']);
// 步骤4: 创建颜色
$textColor = imagecolorallocate($sourceImage, $color[0], $color[1], $color[2]);
// 添加水印文本
imagestring($sourceImage, $font, $x, $y, $watermarkText, $textColor);
// 步骤5: 输出图片
switch ($mimeType) {
case 'image/jpeg':
imagejpeg($sourceImage, $outputPath, 100); // 100%质量
break;
case 'image/png':
imagepng($sourceImage, $outputPath, 9); // 压缩级别9
break;
}
// 释放资源
imagedestroy($sourceImage);
return true;
} catch (Exception $e) {
error_log("水印添加失败: " . $e->getMessage());
return false;
}
}
// 示例用法
// 添加文本水印到图片,位置为右下角,使用内置字体5,白色
$result = addWatermarkWithBuiltInFont(
'path/to/source.jpg',
'path/to/output.jpg',
'Copyright',
'bottom-right',
5,
[255, 255, 255] // 白色
);
if ($result) {
echo "水印添加成功!";
} else {
echo "水印添加失败,请检查错误日志。";
}
?>
```
### 说明:
1. 内置字体:我们使用`imagefontwidth`和`imagefontheight`来计算文本的宽度和高度。注意,内置字体是等宽字体,所以每个字符宽度相同。
2. 位置计算:与之前类似,我们预定义了8个位置(加上中心共9个)的坐标计算,并固定边距为10像素。
3. 颜色:通过`imagecolorallocate`创建颜色,这里使用用户传入的RGB数组。
4. 绘制文本:使用`imagestring`函数,该函数将文本绘制到指定位置。
5. 不支持透明度:由于内置字体函数不支持透明度,所以无法设置半透明。但可以通过设置浅色(如灰色)来降低水印的明显程度。
### 注意事项:
- 内置字体大小有限,且不支持中文(因为内置字体是西文字体)。如果需要中文,必须使用TrueType字体。
- 由于内置字体较小,可能不适合大图片,但可以满足简单的水印需求。
这个方案适用于简单的版权声明,且不需要复杂效果的情况。GD库内置字体处理速度快,不需要额外加载字体文件,适合简单应用场景[^2]。
§§相关问题§§
1. GD库内置字体有哪些局限性?
2. 如何为GD库水印添加阴影效果?
3. 在PHP中,如何读取图片的EXIF数据并添加为水印?[^3]
4. 使用GD库处理图片时,如何避免内存不足的问题?
[^1]: 随着数字媒体的发展,图片水印已经成为保护图片版权、宣传品牌的一种常见手段。本章节将深入探讨如何使用GD库在PHP中添加图片水印,包括水印创建过程、参数设置、位置调整以及应用场景分析。
[^2]: GD库是php处理图形的扩展库,GD库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片,也可以给图片加水印。最新版的GD库支持GIF、JPEG、PNG、WBMP、XBM等格式的图像文件,此外还支持winows下的ttf字体、FreeType等字体显示。通过GD库中的函数可以完成各种点、线、几何图形、文本、颜色的操作和处理。
[^3]: 我们有一个文件夹,里面存放着 300 张照片。每张照片都有拍摄时间的元数据(EXIF 数据)。我们要做的是: 读取每张照片的拍摄时间。在照片的右下角合适的位置添加这个拍摄时间作为水印。保存带有水印的新照片到另一个文件夹中。 所需工具 PHP:我们将使用 PHP 编写代码。GD 库:这是 PHP 内置的一个图像处理库,用来操作图片。EXIF 函数:用于读取照片的元数据(如拍摄时间)。 实现步骤 第一步:准备环境
[^4]: php中的gd图像处理,PHP图像处理(GD库)。①PHP不仅限于只产生HTML的输出,还可以创建与操作多种不同格式的图像文件。PHP提供了一些内置的图像处理函数,也可以使用GD函数库创建新图像或处理已有的图像。目前GD2库支持JPEG、PNG和WBMP格式。</think>### PHP GD库使用内置字体添加水印(支持8个位置)
以下是使用GD库内置字体为图片添加水印的完美解决方案,支持指定8个位置。GD库提供了5种内置字体(编号1-5),这些字体是等宽字体,适用于简单的水印场景[^2][^4]。
#### 完整代码实现
```php
<?php
/**
* 使用GD库内置字体添加水印
* @param string $sourcePath 原始图片路径
* @param string $outputPath 输出图片路径
* @param string $watermarkText 水印文本
* @param string $position 水印位置(默认'center')
* @param int $font 内置字体编号(1-5,默认5)
* @param array $color 文本颜色 [R, G, B](默认白色[255,255,255])
* @param int $margin 边距(像素,默认10)
* @return bool 成功返回true,失败返回false
*/
function addWatermarkWithBuiltInFont(
$sourcePath,
$outputPath,
$watermarkText,
$position = 'center',
$font = 5,
$color = [255, 255, 255],
$margin = 10
) {
try {
// 验证字体编号
if ($font < 1 || $font > 5) {
throw new Exception("字体编号必须在1-5之间");
}
// 加载原始图片
$sourceInfo = getimagesize($sourcePath);
if (!$sourceInfo) {
throw new Exception("无法加载图片: $sourcePath");
}
$mimeType = $sourceInfo['mime'];
switch ($mimeType) {
case 'image/jpeg':
$sourceImage = imagecreatefromjpeg($sourcePath);
break;
case 'image/png':
$sourceImage = imagecreatefrompng($sourcePath);
// 保留PNG透明度
imagealphablending($sourceImage, true);
imagesavealpha($sourceImage, true);
break;
default:
throw new Exception("不支持的格式: $mimeType");
}
$sourceWidth = imagesx($sourceImage);
$sourceHeight = imagesy($sourceImage);
// 计算水印尺寸(内置字体)
$charWidth = imagefontwidth($font);
$charHeight = imagefontheight($font);
$textWidth = $charWidth * strlen($watermarkText);
$textHeight = $charHeight;
// 计算8个位置坐标
$positions = [
'top-left' => ['x' => $margin, 'y' => $margin],
'top-center' => ['x' => ($sourceWidth - $textWidth) / 2, 'y' => $margin],
'top-right' => ['x' => $sourceWidth - $textWidth - $margin, 'y' => $margin],
'middle-left' => ['x' => $margin, 'y' => ($sourceHeight - $textHeight) / 2],
'center' => ['x' => ($sourceWidth - $textWidth) / 2, 'y' => ($sourceHeight - $textHeight) / 2],
'middle-right' => ['x' => $sourceWidth - $textWidth - $margin, 'y' => ($sourceHeight - $textHeight) / 2],
'bottom-left' => ['x' => $margin, 'y' => $sourceHeight - $textHeight - $margin],
'bottom-center' => ['x' => ($sourceWidth - $textWidth) / 2, 'y' => $sourceHeight - $textHeight - $margin],
'bottom-right' => ['x' => $sourceWidth - $textWidth - $margin, 'y' => $sourceHeight - $textHeight - $margin]
];
if (!isset($positions[$position])) {
throw new Exception("无效位置: $position");
}
$pos = $positions[$position];
$x = max(0, $pos['x']); // 确保不超出左边界
$y = max(0, $pos['y']); // 确保不超出上边界
// 创建水印颜色
$textColor = imagecolorallocate($sourceImage, $color[0], $color[1], $color[2]);
// 添加水印文本
imagestring($sourceImage, $font, $x, $y, $watermarkText, $textColor);
// 保存图片
switch ($mimeType) {
case 'image/jpeg':
imagejpeg($sourceImage, $outputPath, 100);
break;
case 'image/png':
imagepng($sourceImage, $outputPath, 9);
break;
}
// 释放资源
imagedestroy($sourceImage);
return true;
} catch (Exception $e) {
error_log("水印错误: " . $e->getMessage());
return false;
}
}
// 使用示例
$result = addWatermarkWithBuiltInFont(
'input.jpg', // 原始图片
'output.jpg', // 输出图片
'© WATERMARK', // 水印文本
'bottom-right', // 位置
5, // 字体大小(1-5)
[255, 0, 0], // 红色文本
20 // 边距
);
if ($result) {
echo "水印添加成功!";
} else {
echo "水印添加失败,请查看错误日志";
}
?>
```
#### 关键功能说明
1. **内置字体支持**:
- 使用GD库内置的5种字体(通过`$font`参数选择)
- 字体尺寸关系:$1 < 2 < 3 < 4 < 5$
- 使用`imagefontwidth()`和`imagefontheight()`计算文本尺寸
2. **8个位置支持**:
- 左上(top-left)、中上(top-center)、右上(top-right)
- 左中(middle-left)、中心(center)、右中(middle-right)
- 左下(bottom-left)、中下(bottom-center)、右下(bottom-right)
- 位置计算基于图片尺寸和水印文本尺寸:$x = \frac{\text{imgWidth} - \text{textWidth}}{2}$
3. **自定义选项**:
- 文本颜色(RGB数组)
- 边距设置(像素)
- 支持JPEG和PNG格式
- 保留PNG图片的透明度[^4]
4. **错误处理**:
- 验证图片格式和字体编号
- 捕获并记录异常
- 确保水印位置不超出图片边界
#### 使用场景建议
- 内置字体适合简单英文水印(不支持中文)
- 字体5(最大号)适合大尺寸图片
- 红色水印在浅色背景上更醒目
- 右下角位置最常用,不影响主要内容[^1]
- 边距20像素可确保水印不被裁剪
GD库提供的高效图像处理能力使其成为PHP中处理水印任务的理想选择[^2]。虽然内置字体功能有限,但对于简单版权声明已足够实用[^4]。