GD库是PHP中用于处理图像的扩展库,它可以创建、操作、输出各种格式的图像,如JPEG、PNG、GIF、WebP等。

在PHP开发中,GD库的应用非常广泛:

  • 生成验证码图片
  • 生成缩略图
  • 给图片加水印
  • 裁剪、缩放、旋转图片
  • 生成图表(柱状图、饼图等)
  • 给图片添加文字
  • 合成多张图片

GD库是PHP的内置扩展,大部分PHP环境都默认开启了GD库。可以用phpinfo()查看GD库是否开启,也可以用extension_loaded('gd')检查。

今天分享PHP GD库图像处理的详解,从基础到进阶,帮你掌握PHP图像处理的各种技巧。

GD库基础

1. 检查GD库是否开启

if (extension_loaded('gd') && function_exists('gd_info')) {
    echo "GD库已开启";
    $info = gd_info();
    print_r($info); // 查看GD库详细信息
} else {
    echo "GD库未开启";
}

gd_info()返回GD库的详细信息,包括版本、支持的图像格式等。

2. 创建图像

创建空白图像

$width = 400;
$height = 300;
$image = imagecreatetruecolor($width, $height); // 创建真彩色图像

imagecreatetruecolor()创建一个真彩色图像,支持24位颜色,推荐使用。

还有imagecreate()创建调色板图像(256色),现在一般不用了。

从文件创建图像

$image = imagecreatefromjpeg('photo.jpg'); // 从JPEG创建
$image = imagecreatefrompng('photo.png');   // 从PNG创建
$image = imagecreatefromgif('photo.gif');   // 从GIF创建
$image = imagecreatefromwebp('photo.webp'); // 从WebP创建(PHP 5.4+)

也可以用imagecreatefromstring()从字符串创建:

$data = file_get_contents('photo.jpg');
$image = imagecreatefromstring($data);

3. 颜色

GD库中,颜色用imagecolorallocate()分配:

$red = imagecolorallocate($image, 255, 0, 0); // 红色
$green = imagecolorallocate($image, 0, 255, 0); // 绿色
$blue = imagecolorallocate($image, 0, 0, 255); // 蓝色
$white = imagecolorallocate($image, 255, 255, 255); // 白色
$black = imagecolorallocate($image, 0, 0, 0); // 黑色
$transparent = imagecolorallocatealpha($image, 0, 0, 0, 127); // 透明

imagecolorallocatealpha()可以设置透明度,0-127,0完全不透明,127完全透明。

4. 填充背景

$image = imagecreatetruecolor(400, 300);
$white = imagecolorallocate($image, 255, 255, 255);
imagefill($image, 0, 0, $white); // 用白色填充整个图像

imagefill()从指定坐标开始填充,直到遇到不同颜色的边界。从(0,0)开始填充,就是填充整个背景。

5. 输出图像

header('Content-Type: image/jpeg');
imagejpeg($image); // 输出JPEG到浏览器

imagejpeg($image, 'output.jpg', 80); // 保存为JPEG文件,质量80

imagepng($image); // 输出PNG
imagepng($image, 'output.png'); // 保存为PNG文件

imagegif($image); // 输出GIF
imagewebp($image, 'output.webp', 80); // 保存为WebP(PHP 5.4+)

注意:输出图像到浏览器前,要设置正确的Content-Type头,并且不能有任何其他输出(包括空格、换行)。

6. 销毁图像

imagedestroy($image); // 销毁图像,释放内存

图像处理完后,要记得销毁图像,释放内存。

基本绘图

1. 画点

$color = imagecolorallocate($image, 255, 0, 0);
imagesetpixel($image, 100, 100, $color); // 在(100,100)画一个红色点

2. 画线

$color = imagecolorallocate($image, 255, 0, 0);
imageline($image, 0, 0, 400, 300, $color); // 从(0,0)到(400,300)画一条红线

3. 画矩形

$color = imagecolorallocate($image, 255, 0, 0);
imagerectangle($image, 50, 50, 350, 250, $color); // 画矩形边框
imagefilledrectangle($image, 50, 50, 350, 250, $color); // 画填充矩形

4. 画椭圆

$color = imagecolorallocate($image, 255, 0, 0);
imageellipse($image, 200, 150, 200, 100, $color); // 画椭圆边框
imagefilledellipse($image, 200, 150, 200, 100, $color); // 画填充椭圆

圆心在(200,150),宽200,高100。宽高相等就是圆。

5. 画多边形

$color = imagecolorallocate($image, 255, 0, 0);
$points = [
    200, 50,   // 点1
    350, 250,  // 点2
    50, 250,   // 点3
];
imagepolygon($image, $points, 3, $color); // 画三角形边框
imagefilledpolygon($image, $points, 3, $color); // 画填充三角形

6. 画弧线

$color = imagecolorallocate($image, 255, 0, 0);
imagearc($image, 200, 150, 200, 100, 0, 180, $color); // 画弧线
// 圆心(200,150),宽200,高100,起始角度0度,结束角度180度

添加文字

1. 用imagestring添加文字

$color = imagecolorallocate($image, 255, 0, 0);
imagestring($image, 5, 100, 100, 'Hello World', $color);
// 字体大小1-5,位置(100,100),文字内容,颜色

imagestring()只能用GD内置的5种字体,不支持中文,适合简单的英文文字。

2. 用imagettftext添加TrueType文字(推荐)

$color = imagecolorallocate($image, 255, 0, 0);
$font = 'fonts/msyh.ttf'; // 字体文件路径
imagettftext($image, 20, 0, 100, 100, $color, $font, '你好,世界');
// 图像,字号20,角度0,位置(100,100),颜色,字体文件,文字

imagettftext()支持TrueType字体,可以显示中文,字体大小任意,推荐使用。

注意:

  • 字体文件路径要正确,建议用绝对路径
  • 中文字体文件(如微软雅黑、宋体、黑体)要确保有版权
  • 角度0是水平,正数是逆时针旋转

3. 文字居中

$font = 'fonts/msyh.ttf';
$fontSize = 20;
$text = '居中文字';
$bbox = imagettfbbox($fontSize, 0, $font, $text);
$textWidth = $bbox[2] - $bbox[0]; // 文字宽度
$textHeight = $bbox[1] - $bbox[7]; // 文字高度
$x = (imagesx($image) - $textWidth) / 2; // 水平居中
$y = (imagesy($image) + $textHeight) / 2; // 垂直居中
imagettftext($image, $fontSize, 0, $x, $y, $color, $font, $text);

图像处理常用操作

1. 生成缩略图

$source = imagecreatefromjpeg('photo.jpg');
$srcWidth = imagesx($source);
$srcHeight = imagesy($source);

$thumbWidth = 200;
$thumbHeight = 200;

$thumb = imagecreatetruecolor($thumbWidth, $thumbHeight);
imagecopyresampled($thumb, $source, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $srcWidth, $srcHeight);

header('Content-Type: image/jpeg');
imagejpeg($thumb);
imagedestroy($source);
imagedestroy($thumb);

imagecopyresampled()是高质量的缩放函数,推荐使用。

2. 等比例缩放

function resizeImage($source, $maxWidth, $maxHeight) {
    $srcWidth = imagesx($source);
    $srcHeight = imagesy($source);
    
    $scale = min($maxWidth / $srcWidth, $maxHeight / $srcHeight);
    $newWidth = (int)($srcWidth * $scale);
    $newHeight = (int)($srcHeight * $scale);
    
    $dest = imagecreatetruecolor($newWidth, $newHeight);
    imagecopyresampled($dest, $source, 0, 0, 0, 0, $newWidth, $newHeight, $srcWidth, $srcHeight);
    
    return $dest;
}

3. 裁剪图片

$source = imagecreatefromjpeg('photo.jpg');
$destWidth = 200;
$destHeight = 200;
$srcX = 100; // 裁剪起始X
$srcY = 100; // 裁剪起始Y

$dest = imagecreatetruecolor($destWidth, $destHeight);
imagecopyresampled($dest, $source, 0, 0, $srcX, $srcY, $destWidth, $destHeight, $destWidth, $destHeight);

imagejpeg($dest, 'cropped.jpg');

4. 居中裁剪(生成正方形缩略图)

function squareThumbnail($source, $size) {
    $srcWidth = imagesx($source);
    $srcHeight = imagesy($source);
    
    // 计算裁剪区域(居中正方形)
    if ($srcWidth > $srcHeight) {
        $srcSize = $srcHeight;
        $srcX = ($srcWidth - $srcHeight) / 2;
        $srcY = 0;
    } else {
        $srcSize = $srcWidth;
        $srcX = 0;
        $srcY = ($srcHeight - $srcWidth) / 2;
    }
    
    $dest = imagecreatetruecolor($size, $size);
    imagecopyresampled($dest, $source, 0, 0, $srcX, $srcY, $size, $size, $srcSize, $srcSize);
    
    return $dest;
}

5. 添加水印

文字水印

$source = imagecreatefromjpeg('photo.jpg');
$color = imagecolorallocatealpha($source, 255, 255, 255, 50); // 半透明白色
$font = 'fonts/msyh.ttf';
$text = '© 我的博客';
imagettftext($source, 20, 0, 20, imagesy($source) - 20, $color, $font, $text);

imagejpeg($source, 'watermarked.jpg');

图片水印

$source = imagecreatefromjpeg('photo.jpg');
$watermark = imagecreatefrompng('watermark.png');

$srcWidth = imagesx($source);
$srcHeight = imagesy($source);
$wmWidth = imagesx($watermark);
$wmHeight = imagesy($watermark);

// 右下角水印
$destX = $srcWidth - $wmWidth - 20;
$destY = $srcHeight - $wmHeight - 20;

imagecopy($source, $watermark, $destX, $destY, 0, 0, $wmWidth, $wmHeight);

imagejpeg($source, 'watermarked.jpg');
imagedestroy($source);
imagedestroy($watermark);

6. 旋转图片

$source = imagecreatefromjpeg('photo.jpg');
$rotated = imagerotate($source, 90, 0); // 旋转90度,背景黑色

imagejpeg($rotated, 'rotated.jpg');
imagedestroy($source);
imagedestroy($rotated);

7. 翻转图片

function flipImage($source, $mode) {
    $width = imagesx($source);
    $height = imagesy($source);
    $dest = imagecreatetruecolor($width, $height);
    
    if ($mode == 'horizontal') {
        // 水平翻转
        for ($x = 0; $x < $width; $x++) {
            imagecopy($dest, $source, $width - $x - 1, 0, $x, 0, 1, $height);
        }
    } elseif ($mode == 'vertical') {
        // 垂直翻转
        for ($y = 0; $y < $height; $y++) {
            imagecopy($dest, $source, 0, $height - $y - 1, 0, $y, $width, 1);
        }
    }
    
    return $dest;
}

8. 调整亮度/对比度/灰度

$source = imagecreatefromjpeg('photo.jpg');

imagefilter($source, IMG_FILTER_BRIGHTNESS, 50); // 调整亮度,-255到255
imagefilter($source, IMG_FILTER_CONTRAST, 30); // 调整对比度,-100到100
imagefilter($source, IMG_FILTER_GRAYSCALE); // 灰度化
imagefilter($source, IMG_FILTER_NEGATE); // 反色
imagefilter($source, IMG_FILTER_EMBOSS); // 浮雕效果
imagefilter($source, IMG_FILTER_GAUSSIAN_BLUR); // 高斯模糊
imagefilter($source, IMG_FILTER_SELECTIVE_BLUR); // 模糊
imagefilter($source, IMG_FILTER_MEAN_REMOVAL); // 移除平均
imagefilter($source, IMG_FILTER_SMOOTH, 5); // 平滑
imagefilter($source, IMG_FILTER_PIXELATE, 10); // 像素化
imagefilter($source, IMG_FILTER_COLORIZE, 255, 0, 0, 50); // 着色

imagejpeg($source, 'filtered.jpg');

imagefilter()提供了很多滤镜效果,可以方便地处理图片。

实战:生成验证码

session_start();

$width = 120;
$height = 40;
$image = imagecreatetruecolor($width, $height);

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

// 生成随机验证码
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$code = '';
for ($i = 0; $i < 4; $i++) {
    $code .= $chars[rand(0, strlen($chars) - 1)];
}
$_SESSION['captcha'] = $code;

// 画干扰点
for ($i = 0; $i < 100; $i++) {
    $color = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
    imagesetpixel($image, rand(0, $width), rand(0, $height), $color);
}

// 画干扰线
for ($i = 0; $i < 5; $i++) {
    $color = imagecolorallocate($image, rand(0, 200), rand(0, 200), rand(0, 200));
    imageline($image, rand(0, $width), rand(0, $height), rand(0, $width), rand(0, $height), $color);
}

// 画验证码文字
$font = 'fonts/arial.ttf';
for ($i = 0; $i < 4; $i++) {
    $color = imagecolorallocate($image, rand(0, 150), rand(0, 150), rand(0, 150));
    $fontSize = rand(18, 24);
    $angle = rand(-15, 15);
    $x = 15 + $i * 25;
    $y = rand(25, 35);
    imagettftext($image, $fontSize, $angle, $x, $y, $color, $font, $code[$i]);
}

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

实战:上传图片生成缩略图

if ($_FILES['image']['error'] == UPLOAD_ERR_OK) {
    $tmpName = $_FILES['image']['tmp_name'];
    $name = $_FILES['image']['name'];
    $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
    
    // 创建图像
    switch ($ext) {
        case 'jpg':
        case 'jpeg':
            $source = imagecreatefromjpeg($tmpName);
            break;
        case 'png':
            $source = imagecreatefrompng($tmpName);
            break;
        case 'gif':
            $source = imagecreatefromgif($tmpName);
            break;
        default:
            die('不支持的图片格式');
    }
    
    // 生成缩略图(最大宽高200)
    $thumb = resizeImage($source, 200, 200);
    
    // 保存
    $newName = uniqid() . '.jpg';
    imagejpeg($source, 'uploads/' . $newName, 80);
    imagejpeg($thumb, 'uploads/thumb_' . $newName, 80);
    
    imagedestroy($source);
    imagedestroy($thumb);
    
    echo "上传成功:" . $newName;
}

最佳实践

  1. 用完销毁图像:图像处理完后,用imagedestroy()销毁,释放内存。
  2. 用imagecopyresampled不用imagecopyresized:前者质量更高。
  3. 用TrueType字体显示中文imagettftext()支持中文,imagestring()不支持。
  4. 注意内存限制:处理大图片时,GD库会占用大量内存,可能超出PHP内存限制。可以用iniset('memorylimit', '256M')临时增加内存。
  5. 图片格式选择:照片用JPEG(有损压缩,文件小),透明图片用PNG,动画用GIF,WebP是新格式,压缩率更高。
  6. 错误处理:图像处理可能失败(文件不存在、格式不支持、内存不足),要做好错误处理。
  7. 缓存处理后的图片:如果图片处理比较耗时,可以把处理后的图片缓存起来,下次直接用缓存。
  8. 安全:用户上传的图片,要验证格式和大小,避免安全风险。不要把用户上传的图片放在可执行目录。

常见问题

1. Call to undefined function imagecreatefromjpeg

原因:GD库没有开启,或者GD库不支持JPEG。 解决:在php.ini中开启extension=gd(PHP 8)或extension=phpgd2.dll(PHP 7),重启服务器。用gdinfo()查看支持的格式。

2. 中文显示乱码或方框

原因:字体不支持中文,或者字体文件路径错误。 解决:用支持中文的TrueType字体(如微软雅黑、宋体),确保字体文件路径正确。

3. 内存溢出

原因:处理大图片时,GD库占用内存超出PHP限制。 解决:用iniset('memorylimit', '256M')增加内存限制,或者先缩小图片再处理。

4. 输出图片时显示乱码

原因:输出图片前有其他输出(空格、换行、BOM头),或者没有设置Content-Type头。 解决:确保输出图片前没有任何输出,设置正确的Content-Type头。PHP文件不要有BOM头。

5. 图片处理后质量变差

原因:JPEG质量设置太低,或者用了imagecopyresized()而不是imagecopyresampled()。 解决:JPEG质量设置80以上,用imagecopyresampled()高质量缩放。

总结

PHP GD库是PHP图像处理的强大工具,掌握它能让你处理各种图片需求。

核心要点:

  1. 基础操作:创建图像(imagecreatetruecolor/imagecreatefromjpeg)、颜色(imagecolorallocate)、填充(imagefill)、输出(imagejpeg/imagepng)、销毁(imagedestroy)
  2. 绘图:画点、画线、画矩形、画椭圆、画多边形、画弧线
  3. 文字:imagestring(简单英文)、imagettftext(TrueType,支持中文)、文字居中
  4. 常用操作:生成缩略图、等比例缩放、裁剪、居中裁剪、添加水印(文字/图片)、旋转、翻转、滤镜
  5. 实战:生成验证码、上传图片生成缩略图
  6. 最佳实践:用完销毁、用高质量函数、TrueType字体、注意内存、选择合适格式、错误处理、缓存、安全

GD库功能强大,能满足大部分图像处理需求。希望这篇文章能帮你掌握PHP GD库图像处理。