GD 庫是 PHP 內建的圖形處理擴展,支援 JPEG、PNG、GIF、WBMP、XPM 等格式。本文系統梳理 GD 核心操作流程,涵蓋圖片讀取、屬性獲取、文字/圖片水印、縮略圖生成(含高質量重採樣),並針對常見坑點給出最佳實踐。
<?php
// 根據副檔名/MIME 動態選擇建立函數
function createImageFromFile(string $path): \GdImage|false
{
$info = getimagesize($path);
if (!$info) return false;
return match ($info[2]) {
IMAGETYPE_JPEG => imagecreatefromjpeg($path),
IMAGETYPE_PNG => imagecreatefrompng($path),
IMAGETYPE_GIF => imagecreatefromgif($path),
IMAGETYPE_WBMP => imagecreatefromwbmp($path),
default => false,
};
}
// 使用範例
$img = createImageFromFile('photo.jpg');
if (!$img) {
die('不支援的圖片格式或檔案損壞');
}
// 輸出至瀏覽器
header('Content-Type: image/jpeg');
imagejpeg($img);
imagedestroy($img);
關鍵點:imagecreatefromjpeg() 等函數是根據檔案內容而非副檔名解碼。若將 .jpg 強改為 .png,imagecreatefrompng() 仍會失敗,因為檔案標頭仍是 JPEG。
<?php
$img = imagecreatefromjpeg('photo.jpg');
// GD 內建函數
$width = imagesx($img); // 寬度
$height = imagesy($img); // 高度
$type = image_type_to_mime_type(IMAGETYPE_JPEG); // MIME
// 更豐富的資訊:getimagesize()
$info = getimagesize('photo.jpg');
/*
$info[0] = 寬度
$info[1] = 高度
$info[2] = 類型常數 (IMAGETYPE_JPEG=2, IMAGETYPE_PNG=3...)
$info[3] = width="xxx" height="yyy" 字串,可直接用於 <img> 標籤
$info['mime'] = MIME 類型
$info['channels'] = 通道數 (3=RGB, 4=RGBA)
$info['bits'] = 每通道位數
*/
echo "圖片尺寸:{$info[0]} x {$info[1]}";
echo "類型常數:{$info[2]}"; // 1=GIF, 2=JPG, 3=PNG, 4=SWF, 5=PSD, 6=BMP...
<?php
/**
* 給圖片添加文字水印
* @param string $srcPath 源圖路徑
* @param string $dstPath 輸出路徑(覆蓋源檔可傳同值)
* @param string $text 水印文字
* @param int $pos 位置:0隨機 1左上 2置中 3右下
* @param int $size 字體大小
* @param string $color 十六進位顏色 #RRGGBB
* @param string $fontPath TTF 字體路徑
*/
function addTextWatermark(
string $srcPath,
string $dstPath,
string $text,
int $pos = 2,
int $size = 20,
string $color = '#FFFFFF',
string $fontPath = 'C:/Windows/Fonts/simhei.ttf' // Linux 常用 /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
): bool
{
if (!file_exists($srcPath)) return false;
$info = getimagesize($srcPath);
$srcImg = match ($info[2]) {
IMAGETYPE_JPEG => imagecreatefromjpeg($srcPath),
IMAGETYPE_PNG => imagecreatefrompng($srcPath),
IMAGETYPE_GIF => imagecreatefromgif($srcPath),
default => false,
};
if (!$srcImg) return false;
$imgW = imagesx($srcImg);
$imgH = imagesy($srcImg);
// 計算文字邊界框
$box = imagettfbbox($size, 0, $fontPath, $text);
$textW = $box[2] - $box[0];
$textH = $box[3] - $box[7];
if ($imgW < $textW || $imgH < $textH) {
imagedestroy($srcImg);
return false; // 圖片太小無法容納水印
}
// 位置計算
switch ($pos) {
case 0: $x = rand(0, $imgW - $textW); $y = rand(0, $imgH - $textH); break;
case 1: $x = 10; $y = $textH + 10; break;
case 2: $x = ($imgW - $textW) / 2; $y = ($imgH + $textH) / 2; break;
case 3: $x = $imgW - $textW - 10; $y = $imgH - 10; break;
default: $x = 10; $y = $textH + 10;
}
// 顏色解析
$r = hexdec(substr($color, 1, 2));
$g = hexdec(substr($color, 3, 2));
$b = hexdec(substr($color, 5, 2));
$textColor = imagecolorallocatealpha($srcImg, $r, $g, $b, 30); // 30% 透明度
// 關鍵:啟用 Alpha 混合,否則透明度不生效
imagealphablending($srcImg, true);
imagesavealpha($srcImg, true);
imagettftext($srcImg, $size, 0, $x, $y, $textColor, $fontPath, $text);
// 按原格式儲存
$saved = match ($info[2]) {
IMAGETYPE_JPEG => imagejpeg($srcImg, $dstPath, 90),
IMAGETYPE_PNG => imagepng($srcImg, $dstPath, 6),
IMAGETYPE_GIF => imagegif($srcImg, $dstPath),
default => false,
};
imagedestroy($srcImg);
return $saved;
}
| 函數 | 速度 | 品質 | 適用場景 |
|---|---|---|---|
imagecopyresized() |
快 | 較差(鋸齒明顯) | 即時預覽、低品質需求 |
imagecopyresampled() |
稍慢 | 優秀(雙三次插值) | 正式縮略圖、生產環境 |
<?php
/**
* 高質量縮略圖(等比例縮放,支援最大寬高限制)
*/
function createThumbnail(
string $srcPath,
string $dstPath,
int $maxW = 300,
int $maxH = 300,
int $quality = 85
): bool
{
$info = getimagesize($srcPath);
$srcImg = match ($info[2]) {
IMAGETYPE_JPEG => imagecreatefromjpeg($srcPath),
IMAGETYPE_PNG => imagecreatefrompng($srcPath),
IMAGETYPE_GIF => imagecreatefromgif($srcPath),
default => false,
};
if (!$srcImg) return false;
$srcW = imagesx($srcImg);
$srcH = imagesy($srcImg);
// 計算目標尺寸(等比例)
$ratio = min($maxW / $srcW, $maxH / $srcH);
if ($ratio >= 1) {
// 原圖已小於限制,直接複製
return copy($srcPath, $dstPath);
}
$dstW = (int)round($srcW * $ratio);
$dstH = (int)round($srcH * $ratio);
// 建立真彩色畫布(關鍵:imagecreatetruecolor 而非 imagecreate)
$dstImg = imagecreatetruecolor($dstW, $dstH);
// 保留透明通道(PNG/GIF)
if ($info[2] === IMAGETYPE_PNG || $info[2] === IMAGETYPE_GIF) {
imagealphablending($dstImg, false);
imagesavealpha($dstImg, true);
$transparent = imagecolorallocatealpha($dstImg, 255, 255, 255, 127);
imagefill($dstImg, 0, 0, $transparent);
}
// 核心:重採樣縮放
imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH);
// 輸出
$saved = match ($info[2]) {
IMAGETYPE_JPEG => imagejpeg($dstImg, $dstPath, $quality),
IMAGETYPE_PNG => imagepng($dstImg, $dstPath, 6),
IMAGETYPE_GIF => imagegif($dstImg, $dstPath),
default => false,
};
imagedestroy($srcImg);
imagedestroy($dstImg);
return $saved;
}
memory_limit,或分塊處理。imagecreatetruecolor + imagesavealpha(true) + imagealphablending(false)。imagettftext 需絕對路徑;Linux 下確認 php-gd 編譯支援 FreeType,且字體檔案可讀。header('Content-Type: image/...'),且前後不能有任何空白字元。GD 雖非 ImageMagick 那般強大,但無需外部依賴、部署簡單,足以應對多數 Web 圖片處理需求。掌握「讀取→計算→繪製→輸出」四步流程,並善用 imagecopyresampled 與 Alpha 混合,即可產出專業級水印圖與縮略圖。