怎样用PHP的GD库或Imagick扩展动态生成图像水印

wen PHP项目 49

本文目录导读:

怎样用PHP的GD库或Imagick扩展动态生成图像水印

  1. 使用GD库生成水印
  2. 使用Imagick扩展生成水印
  3. 批量处理水印
  4. 性能对比与选择建议
  5. 注意事项

我来详细介绍使用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。

注意事项

  1. 字体文件:使用文字水印时需要确保字体文件路径正确
  2. 权限问题:确保目录有写入权限
  3. 内存限制:处理大图片时可能需要调整PHP内存限制
  4. 错误处理:添加适当的错误处理和日志记录
  5. 缓存机制:对于频繁访问的图片,建议添加缓存机制

抱歉,评论功能暂时关闭!