Skip to content

GD 图像处理

PHP 的 GD 扩展是最常用的图像处理库,支持 JPEG、PNG、GIF、WebP、AVIF 等格式的创建、编辑和输出。虽然功能不如 ImageMagick 全面,但对于常见的缩略图生成、水印添加、验证码生成等场景完全够用。

前置知识

阅读本节前,建议先了解:PHP 基础语法文件系统操作

基础概念

安装

bash
# 编译安装
./configure --with-gd

# Ubuntu/Debian
sudo apt-get install php-gd

# 检查支持格式
php -r "print_r(gd_info());"

创建图像

基本操作

php
<?php
declare(strict_types=1);

// 创建 200x100 的真彩色图像
$image = imagecreatetruecolor(200, 100);

// 分配颜色
$red   = imagecolorallocate($image, 255, 0, 0);
$green = imagecolorallocate($image, 0, 255, 0);
$blue  = imagecolorallocate($image, 0, 0, 255);
$white = imagecolorallocate($image, 255, 255, 255);

// 填充背景
imagefill($image, 0, 0, $white);

// 绘制矩形
imagerectangle($image, 10, 10, 90, 50, $red);

// 绘制填充矩形
imagefilledrectangle($image, 110, 10, 190, 50, $green);

// 绘制线条
imageline($image, 0, 80, 200, 80, $blue);

// 输出为 PNG
header('Content-Type: image/png');
imagepng($image);

// 释放内存
imagedestroy($image);

输出格式

php
<?php
declare(strict_types=1);

$image = imagecreatetruecolor(200, 200);

// 输出为 JPEG(质量 0~100)
header('Content-Type: image/jpeg');
imagejpeg($image, null, 85);

// 输出为 PNG(压缩级别 0~9)
header('Content-Type: image/png');
imagepng($image, null, 6);

// 输出为 GIF
header('Content-Type: image/gif');
imagegif($image);

// 输出为 WebP(PHP 5.5+)
header('Content-Type: image/webp');
imagewebp($image, null, 80);

// 保存到文件
imagepng($image, '/tmp/output.png', 9);
imagejpeg($image, '/tmp/output.jpg', 90);
imagewebp($image, '/tmp/output.webp', 80);

imagedestroy($image);

图片处理

缩略图生成

php
<?php
declare(strict_types=1);

/**
 * 生成缩略图(保持宽高比)
 */
function createThumbnail(
    string $sourcePath,
    string $destPath,
    int $maxWidth,
    int $maxHeight
): bool {
    // 获取原图尺寸
    [$width, $height, $type] = getimagesize($sourcePath);

    if ($width === 0 || $height === 0) {
        return false;
    }

    // 计算缩放比例
    $ratio = min($maxWidth / $width, $maxHeight / $height);
    $newWidth = (int) ($width * $ratio);
    $newHeight = (int) ($height * $ratio);

    // 创建目标图像
    $thumb = imagecreatetruecolor($newWidth, $newHeight);

    // 创建源图像(根据格式)
    $source = match ($type) {
        IMAGETYPE_JPEG => imagecreatefromjpeg($sourcePath),
        IMAGETYPE_PNG  => imagecreatefrompng($sourcePath),
        IMAGETYPE_GIF  => imagecreatefromgif($sourcePath),
        IMAGETYPE_WEBP => imagecreatefromwebp($sourcePath),
        default        => throw new RuntimeException("不支持的图片格式"),
    };

    // PNG 保留透明通道
    if ($type === IMAGETYPE_PNG) {
        imagealphablending($thumb, false);
        imagesavealpha($thumb, true);
        $transparent = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
        imagefill($thumb, 0, 0, $transparent);
    }

    // 缩放复制
    imagecopyresampled($thumb, $source, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);

    // 保存
    $result = match ($type) {
        IMAGETYPE_JPEG => imagejpeg($thumb, $destPath, 85),
        IMAGETYPE_PNG  => imagepng($thumb, $destPath, 6),
        IMAGETYPE_GIF  => imagegif($thumb, $destPath),
        IMAGETYPE_WEBP => imagewebp($thumb, $destPath, 80),
        default        => false,
    };

    imagedestroy($thumb);
    imagedestroy($source);

    return $result;
}

// 使用示例
// createThumbnail('/path/to/large.jpg', '/path/to/thumb.jpg', 200, 150);

水印添加

php
<?php
declare(strict_types=1);

/**
 * 添加文字水印
 */
function addTextWatermark(
    string $imagePath,
    string $text,
    string $outputPath,
    int $fontSize = 20,
    string $fontFile = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
): void {
    $image = imagecreatefromstring(file_get_contents($imagePath));
    $width = imagesx($image);
    $height = imagesy($image);

    // 创建半透明白色
    $white = imagecolorallocatealpha($image, 255, 255, 255, 60);

    // 计算文字位置(右下角)
    $bbox = imagettfbbox($fontSize, 0, $fontFile, $text);
    $textWidth = $bbox[2] - $bbox[0];
    $textHeight = $bbox[1] - $bbox[7];
    $x = $width - $textWidth - 10;
    $y = $height - 10;

    // 添加文字
    imagettftext($image, $fontSize, 0, $x, $y, $white, $fontFile, $text);

    // 保存
    $ext = strtolower(pathinfo($imagePath, PATHINFO_EXTENSION));
    match ($ext) {
        'jpg', 'jpeg' => imagejpeg($image, $outputPath, 90),
        'png'         => imagepng($image, $outputPath),
        'webp'        => imagewebp($image, $outputPath, 80),
        default       => imagepng($image, $outputPath),
    };

    imagedestroy($image);
}

验证码生成

php
<?php
declare(strict_types=1);

/**
 * 生成验证码图片
 */
function generateCaptcha(int $length = 6, int $width = 120, int $height = 40): array
{
    $image = imagecreatetruecolor($width, $height);

    // 背景
    $bgColor = imagecolorallocate($image, 240, 240, 240);
    imagefill($image, 0, 0, $bgColor);

    // 生成随机验证码
    $code = '';
    $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789';

    for ($i = 0; $i < $length; $i++) {
        $char = $chars[random_int(0, strlen($chars) - 1)];
        $code .= $char;

        // 随机颜色
        $color = imagecolorallocate($image, random_int(0, 150), random_int(0, 150), random_int(0, 150));

        // 随机位置和角度
        $x = 10 + ($i * ($width - 20) / $length);
        $y = $height / 2 + random_int(-5, 5);
        $angle = random_int(-15, 15);

        imagettftext($image, random_int(18, 24), $angle, (int) $x, (int) $y, $color,
            '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', $char);
    }

    // 添加干扰线
    for ($i = 0; $i < 5; $i++) {
        $lineColor = imagecolorallocate($image, random_int(150, 255), random_int(150, 255), random_int(150, 255));
        imageline($image,
            random_int(0, $width), random_int(0, $height),
            random_int(0, $width), random_int(0, $height),
            $lineColor
        );
    }

    // 添加噪点
    for ($i = 0; $i < 100; $i++) {
        $dotColor = imagecolorallocate($image, random_int(100, 255), random_int(100, 255), random_int(100, 255));
        imagesetpixel($image, random_int(0, $width), random_int(0, $height), $dotColor);
    }

    // 输出
    header('Content-Type: image/png');
    imagepng($image);
    imagedestroy($image);

    return ['code' => $code];
}

注意事项

  • 大图操作注意内存限制(memory_limit
  • PNG 透明通道需要 imagealphablendingimagesavealpha
  • WebP 格式需要 PHP 5.5+ 和 libwebp

下一节

继续学习:ImageMagick

参考链接