PHP 中处理图像的利器 GD库

PHP 中处理图像的利器 GD库

在 PHP 开发中,GD 库是处理图像的核心利器:生成验证码、制作缩略图、添加水印、绘制简单图表...... 这些高频需求都能通过 GD 库轻松实现。

开启需修改 php.ini,取消 extension=gd(Windows)或 extension=gd.so(Linux)前的注释,重启 Web 服务即可。

GD 库基本操作流程

所有 GD 操作都遵循 "创建画布 → 分配颜色 → 绘制内容 → 输出 / 保存 → 销毁资源" 的流程:

php 复制代码
<?php
// 1. 创建画布(宽 400,高 200)
$image = imagecreatetruecolor(400, 200);

// 2. 分配颜色(RGB 值)
$white = imagecolorallocate($image, 255, 255, 255); // 白色
$black = imagecolorallocate($image, 0, 0, 0);       // 黑色

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

// 4. 绘制内容(比如写一行字)
imagestring($image, 5, 100, 90, 'Hello GD!', $black);

// 5. 输出图像(或保存到文件)
header('Content-Type: image/png'); // 告诉浏览器输出的是 PNG 图片
imagepng($image);

// 6. 销毁资源,释放内存
imagedestroy($image);
?>

常用功能

绘制基本图形

GD 库支持绘制直线、矩形、圆形、椭圆等基础图形,适合制作简单图表或标记。

函数 说明
imageline() 绘制直线
imagerectangle() 绘制矩形(边框)
imagefilledrectangle() 绘制填充矩形
imageellipse() 绘制椭圆(圆形是椭圆的特例)
imagefilledellipse() 绘制填充椭圆
php 复制代码
// 创建画布
$image = imagecreatetruecolor(400, 300);
$white = imagecolorallocate($image, 255, 255, 255);
$red = imagecolorallocate($image, 255, 0, 0);
$blue = imagecolorallocate($image, 0, 0, 255);
$green = imagecolorallocate($image, 0, 255, 0);

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

// 1. 绘制红色直线(从 x1,y1 到 x2,y2)
imageline($image, 50, 50, 350, 50, $red);

// 2. 绘制蓝色矩形边框(x1,y1 左上角,x2,y2 右下角)
imagerectangle($image, 50, 80, 150, 180, $blue);

// 3. 绘制绿色填充矩形
imagefilledrectangle($image, 200, 80, 350, 180, $green);

// 4. 绘制红色填充圆形(圆心 x,y,宽高相同即为圆)
imagefilledellipse($image, 200, 240, 80, 80, $red);

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

生成缩略图

网站上传图片时,生成缩略图是刚需。GD 库通过 imagecopyresampled() 实现高质量缩放。

  • imagecreatefromjpeg() / imagecreatefrompng():从现有图片创建画布资源。
  • imagecopyresampled():重采样复制图像(比 imagecopyresized() 更清晰,推荐使用)。
php 复制代码
/**
 * 生成等比例缩略图
 * @param string $srcPath 原图路径
 * @param string $destPath 缩略图保存路径
 * @param int $maxWidth 最大宽度
 * @param int $maxHeight 最大高度
 */
function createThumbnail($srcPath, $destPath, $maxWidth = 200, $maxHeight = 200) {
    // 获取原图信息
    list($srcWidth, $srcHeight, $type) = getimagesize($srcPath);
    
    // 根据图片类型创建画布
    switch ($type) {
        case IMAGETYPE_JPEG:
            $srcImage = imagecreatefromjpeg($srcPath);
            break;
        case IMAGETYPE_PNG:
            $srcImage = imagecreatefrompng($srcPath);
            break;
        default:
            return false;
    }
    
    // 计算等比例缩放后的尺寸
    $scale = min($maxWidth / $srcWidth, $maxHeight / $srcHeight);
    $destWidth = $srcWidth * $scale;
    $destHeight = $srcHeight * $scale;
    
    // 创建缩略图画布
    $destImage = imagecreatetruecolor($destWidth, $destHeight);
    
    // 处理 PNG 透明背景(可选,若不需要可省略)
    if ($type == IMAGETYPE_PNG) {
        $transparent = imagecolorallocatealpha($destImage, 255, 255, 255, 127);
        imagefill($destImage, 0, 0, $transparent);
        imagesavealpha($destImage, true);
    }
    
    // 重采样复制(核心步骤)
    imagecopyresampled(
        $destImage, $srcImage, // 目标画布、源画布
        0, 0, 0, 0,            // 目标 x,y、源 x,y
        $destWidth, $destHeight,// 目标宽高
        $srcWidth, $srcHeight   // 源宽高
    );
    
    // 保存缩略图
    switch ($type) {
        case IMAGETYPE_JPEG:
            imagejpeg($destImage, $destPath, 90); // 90 是 JPEG 质量
            break;
        case IMAGETYPE_PNG:
            imagepng($destImage, $destPath);
            break;
    }
    
    // 销毁资源
    imagedestroy($srcImage);
    imagedestroy($destImage);
    return true;
}

添加水印

文字水印

php 复制代码
/**
 * 添加文字水印
 * @param string $srcPath 原图路径
 * @param string $text 水印文字
 * @param string $fontPath 字体文件路径(需支持中文,比如 simhei.ttf)
 */
function addTextWatermark($srcPath, $text, $fontPath = './simhei.ttf') {
    // 获取原图信息
    list($width, $height, $type) = getimagesize($srcPath);
    switch ($type) {
        case IMAGETYPE_JPEG:
            $image = imagecreatefromjpeg($srcPath);
            break;
        case IMAGETYPE_PNG:
            $image = imagecreatefrompng($srcPath);
            break;
        default:
            return false;
    }
    
    // 分配水印颜色(半透明白色)
    $watermarkColor = imagecolorallocatealpha($image, 255, 255, 255, 50); // 50 是透明度(0-127,越大越透明)
    
    // 设置字体大小
    $fontSize = 20;
    
    // 计算文字位置(右下角)
    $bbox = imagettfbbox($fontSize, 0, $fontPath, $text);
    $textWidth = $bbox[2] - $bbox[0];
    $textHeight = $bbox[1] - $bbox[7];
    $x = $width - $textWidth - 20; // 距离右边 20px
    $y = $height - $textHeight - 20; // 距离下边 20px
    
    // 写入文字(使用 TrueType 字体,支持中文)
    imagettftext($image, $fontSize, 0, $x, $y, $watermarkColor, $fontPath, $text);
    
    // 保存图片
    $destPath = './watermark_text.jpg';
    switch ($type) {
        case IMAGETYPE_JPEG:
            imagejpeg($image, $destPath, 90);
            break;
        case IMAGETYPE_PNG:
            imagepng($image, $destPath);
            break;
    }
    
    imagedestroy($image);
    return $destPath;
}

图片水印

php 复制代码
/**
 * 添加图片水印
 * @param string $srcPath 原图路径
 * @param string $watermarkPath 水印图片路径(建议 PNG 透明图)
 */
function addImageWatermark($srcPath, $watermarkPath) {
    // 获取原图和水印图信息
    list($srcWidth, $srcHeight, $srcType) = getimagesize($srcPath);
    list($wmWidth, $wmHeight, $wmType) = getimagesize($watermarkPath);
    
    // 创建画布
    switch ($srcType) {
        case IMAGETYPE_JPEG:
            $srcImage = imagecreatefromjpeg($srcPath);
            break;
        case IMAGETYPE_PNG:
            $srcImage = imagecreatefrompng($srcPath);
            break;
        default:
            return false;
    }
    $wmImage = imagecreatefrompng($watermarkPath); // 假设水印是 PNG
    
    // 计算水印位置(右下角)
    $x = $srcWidth - $wmWidth - 20;
    $y = $srcHeight - $wmHeight - 20;
    
    // 合并水印(保留 PNG 透明度)
    imagecopy($srcImage, $wmImage, $x, $y, 0, 0, $wmWidth, $wmHeight);
    
    // 保存图片
    $destPath = './watermark_image.jpg';
    switch ($srcType) {
        case IMAGETYPE_JPEG:
            imagejpeg($srcImage, $destPath, 90);
            break;
        case IMAGETYPE_PNG:
            imagepng($srcImage, $destPath);
            break;
    }
    
    imagedestroy($srcImage);
    imagedestroy($wmImage);
    return $destPath;
}

生成验证码

验证码是防止恶意注册、刷接口的常用手段,GD 库生成验证码的核心是 "随机字符 + 干扰线 + 噪点"。

php 复制代码
<?php
session_start(); // 开启 Session,用于保存验证码

// 1. 创建画布
$width = 120;
$height = 40;
$image = imagecreatetruecolor($width, $height);

// 2. 分配颜色
$white = imagecolorallocate($image, 255, 255, 255);
$gray = imagecolorallocate($image, 200, 200, 200);
$darkGray = imagecolorallocate($image, 100, 100, 100);

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

// 4. 绘制干扰线(3 条)
for ($i = 0; $i < 3; $i++) {
    $lineColor = imagecolorallocate($image, rand(100, 200), rand(100, 200), rand(100, 200));
    imageline($image, rand(0, $width), rand(0, $height), rand(0, $width), rand(0, $height), $lineColor);
}

// 5. 绘制噪点(50 个)
for ($i = 0; $i < 50; $i++) {
    $dotColor = imagecolorallocate($image, rand(50, 150), rand(50, 150), rand(50, 150));
    imagesetpixel($image, rand(0, $width), rand(0, $height), $dotColor);
}

// 6. 生成随机验证码
$chars = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'; // 去掉易混淆的 0、1、O、l
$code = '';
for ($i = 0; $i < 4; $i++) {
    $code .= $chars[rand(0, strlen($chars) - 1)];
}

// 保存到 Session,用于后续验证
$_SESSION['captcha'] = strtolower($code);

// 7. 写入验证码文字
$fontSize = 16;
$fontPath = './simhei.ttf'; // 可选,若没有可用 imagestring
for ($i = 0; $i < 4; $i++) {
    $charColor = imagecolorallocate($image, rand(0, 100), rand(0, 100), rand(0, 100));
    $x = 15 + $i * 25;
    $y = rand(25, 35);
    imagettftext($image, $fontSize, rand(-10, 10), $x, $y, $charColor, $fontPath, $code[$i]);
}

// 8. 输出图像
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
?>

注意事项

  1. 记得销毁资源 :每次 GD 操作后,务必用 imagedestroy() 销毁图像资源,避免内存泄漏。
  2. 输出前无任何输出 :在 header('Content-Type: image/png') 前,不能有任何 HTML 标签、空格或换行,否则会导致图像无法显示。
  3. 处理大图片注意内存 :处理高分辨率图片时,可能会超出 PHP 内存限制,可在代码开头临时调整:ini_set('memory_limit', '256M');
  4. 中文支持用 TrueType 字体imagestring() 不支持中文,需用 imagettftext() 配合 .ttf 字体文件(如 simhei.ttf 黑体)。
  5. 优先使用 imagecopyresampled() :缩放图片时,imagecopyresampled() 会进行重采样,生成的缩略图更清晰,不要用 imagecopyresized()
相关推荐
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
红尘散仙6 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记7 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
isyangli_blog7 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
会编程的土豆7 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
Cosolar7 小时前
从零写一个 Attention Is All You Need
人工智能·面试·架构
喵个咪8 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6168 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364578 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao9 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端