PHP 图像处理

Creating images, resizing, cropping, watermarking and output formats with GD.

Intermediate
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
水印已叠加
300x200
imagecopymerge 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

Friends & Partners