PHP 图像处理
Creating images, resizing, cropping, watermarking and output formats with GD.
Key PointsGD emits binary — set `Content-Type: image/*` and produce no other output.
Checking GD
PHP
<?php
echo extension_loaded("gd") ? "GD 已加载" : "GD 未加载", "\n";
$info = gd_info();
foreach (["JPEG Support", "PNG Support", "GIF Read Support", "WebP Support"] as $k) {
echo $k . ": " . (($info[$k] ?? false) ? "支持" : "不支持") . "\n";
}Output
GD 已加载
JPEG Support: 支持
PNG Support: 支持
GIF Read Support: 支持
WebP Support: 支持Creating an image
PHP
<?php
$w = 200;
$h = 80;
$img = imagecreatetruecolor($w, $h);
$bg = imagecolorallocate($img, 240, 244, 248);
$text = imagecolorallocate($img, 30, 41, 59);
imagefilledrectangle($img, 0, 0, $w, $h, $bg);
// 内置字体(1-5 号),中文需要 imagettftext + 字体文件
imagestring($img, 5, 20, 30, "Hello GD", $text);
$path = __DIR__ . "/demo.png";
imagepng($img, $path);
imagedestroy($img);
$info = getimagesize($path);
echo "尺寸: {$info[0]}x{$info[1]}\n";
echo filesize($path) > 0 ? "已生成" : "生成失败", "\n";
unlink($path);Output
尺寸: 200x80
已生成imagestring cannot render Chinese. Use imagettftext with a TTF containing the glyphs.Resize and crop
PHP
<?php
function makeThumb(string $src, string $dst, int $maxW, int $maxH): bool
{
[$w, $h, $type] = getimagesize($src);
$ratio = min($maxW / $w, $maxH / $h);
$nw = max(1, (int)round($w * $ratio));
$nh = max(1, (int)round($h * $ratio));
$srcImg = match ($type) {
IMAGETYPE_JPEG => imagecreatefromjpeg($src),
IMAGETYPE_PNG => imagecreatefrompng($src),
IMAGETYPE_GIF => imagecreatefromgif($src),
default => false,
};
if ($srcImg === false) {
return false;
}
$dstImg = imagecreatetruecolor($nw, $nh);
// PNG 透明处理
imagealphablending($dstImg, false);
imagesavealpha($dstImg, true);
imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $nw, $nh, $w, $h);
$ok = imagepng($dstImg, $dst);
imagedestroy($srcImg);
imagedestroy($dstImg);
return $ok;
}
echo "缩略图函数已定义\n";Output
缩略图函数已定义imagecopyresampled resamples smoothly; imagecopyresized produces jagged output. Always use the former for thumbnails.
PNG transparency needs three steps: truecolor canvas,
imagealphablending(false), imagesavealpha(true). Skip the last two and transparent areas turn black.Output to the browser
PHP
<?php
$img = imagecreatetruecolor(120, 60);
$c = imagecolorallocate($img, 59, 130, 246);
imagefilledrectangle($img, 0, 0, 120, 60, $c);
header("Content-Type: image/png");
header("Cache-Control: max-age=3600");
imagepng($img);
imagedestroy($img);Output
(二进制 PNG 数据)No output before the image — not even whitespace or a BOM, or the PNG corrupts. Keep no blank lines before
<?php or after ?>.Watermark
PHP
<?php
$base = imagecreatetruecolor(300, 200);
imagefilledrectangle($base, 0, 0, 300, 200, imagecolorallocate($base, 200, 200, 200));
$mark = imagecreatetruecolor(100, 30);
imagefilledrectangle($mark, 0, 0, 100, 30, imagecolorallocate($mark, 0, 0, 0));
// 合并(最后一个参数是不透明度 0-100)
imagecopymerge($base, $mark, 190, 160, 0, 0, 100, 30, 40);
echo "水印已叠加\n";
echo imagesx($base) . "x" . imagesy($base) . "\n";
imagedestroy($base);
imagedestroy($mark);Output
水印已叠加
300x200imagecopymerge handles PNG alpha poorly — semi-transparent watermarks get black fringes. Use imagecopy with imagecolorallocatealpha instead.Caveats
- Memory —— a 4000×3000 image is ~48MB; check
memory_limit - Distrust uploads —— verify with
getimagesize - Downscale first —— never process an 8000px original directly
- Imagick is stronger —— for colour management, EXIF, vectors
环境检查
PHP
<?php
echo extension_loaded("gd") ? "GD 已加载" : "GD 未加载", "\n";
$info = gd_info();
foreach (["JPEG Support", "PNG Support", "GIF Read Support", "WebP Support"] as $k) {
echo $k . ": " . (($info[$k] ?? false) ? "支持" : "不支持") . "\n";
}Output
GD 已加载
JPEG Support: 支持
PNG Support: 支持
GIF Read Support: 支持
WebP Support: 支持创建图像
PHP
<?php
$w = 200;
$h = 80;
$img = imagecreatetruecolor($w, $h);
$bg = imagecolorallocate($img, 240, 244, 248);
$text = imagecolorallocate($img, 30, 41, 59);
imagefilledrectangle($img, 0, 0, $w, $h, $bg);
// 内置字体(1-5 号),中文需要 imagettftext + 字体文件
imagestring($img, 5, 20, 30, "Hello GD", $text);
$path = __DIR__ . "/demo.png";
imagepng($img, $path);
imagedestroy($img);
$info = getimagesize($path);
echo "尺寸: {$info[0]}x{$info[1]}\n";
echo filesize($path) > 0 ? "已生成" : "生成失败", "\n";
unlink($path);Output
尺寸: 200x80
已生成imagestring 不支持中文,会输出乱码方块。中文必须用 imagettftext 并指定一个含中文字形的 TTF 字体文件。缩放与裁剪
PHP
<?php
function makeThumb(string $src, string $dst, int $maxW, int $maxH): bool
{
[$w, $h, $type] = getimagesize($src);
$ratio = min($maxW / $w, $maxH / $h);
$nw = max(1, (int)round($w * $ratio));
$nh = max(1, (int)round($h * $ratio));
$srcImg = match ($type) {
IMAGETYPE_JPEG => imagecreatefromjpeg($src),
IMAGETYPE_PNG => imagecreatefrompng($src),
IMAGETYPE_GIF => imagecreatefromgif($src),
default => false,
};
if ($srcImg === false) {
return false;
}
$dstImg = imagecreatetruecolor($nw, $nh);
// PNG 透明处理
imagealphablending($dstImg, false);
imagesavealpha($dstImg, true);
imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $nw, $nh, $w, $h);
$ok = imagepng($dstImg, $dst);
imagedestroy($srcImg);
imagedestroy($dstImg);
return $ok;
}
echo "缩略图函数已定义\n";Output
缩略图函数已定义imagecopyresampled 会做重采样,比 imagecopyresized 平滑得多。生成缩略图必须用前者,后者锯齿严重。
PNG 透明要三步:
imagecreatetruecolor → imagealphablending($dst, false) → imagesavealpha($dst, true)。漏掉后两步,透明区域会变成黑色。输出到浏览器
PHP
<?php
$img = imagecreatetruecolor(120, 60);
$c = imagecolorallocate($img, 59, 130, 246);
imagefilledrectangle($img, 0, 0, 120, 60, $c);
header("Content-Type: image/png");
header("Cache-Control: max-age=3600");
imagepng($img);
imagedestroy($img);Output
(二进制 PNG 数据)**输出图像前不能有任何
echo、空格、BOM**,否则图片会损坏(浏览器收到「文本 + 二进制」)。文件开头别留空行,?> 后别留空行。加水印
PHP
<?php
$base = imagecreatetruecolor(300, 200);
imagefilledrectangle($base, 0, 0, 300, 200, imagecolorallocate($base, 200, 200, 200));
$mark = imagecreatetruecolor(100, 30);
imagefilledrectangle($mark, 0, 0, 100, 30, imagecolorallocate($mark, 0, 0, 0));
// 合并(最后一个参数是不透明度 0-100)
imagecopymerge($base, $mark, 190, 160, 0, 0, 100, 30, 40);
echo "水印已叠加\n";
echo imagesx($base) . "x" . imagesy($base) . "\n";
imagedestroy($base);
imagedestroy($mark);Output
水印已叠加
300x200imagecopymerge 对 PNG 的 alpha 通道支持不好,半透明水印会出现黑边。要正确处理透明度,用 imagecopy 加 imagecolorallocatealpha。注意事项
- 内存 —— 一张 4000×3000 的图约 48MB(4 字节/像素),先看
memory_limit - 不要信任上传文件 —— 用
getimagesize确认是真图片 - 大图先缩小再处理 —— 别在 8000px 的原图上直接操作
- Imagick 更强 —— 需要色彩管理、EXIF、矢量时换 Imagick