/**
* 旋轉圖片指定角度並另存新檔
*
* @param string $srcPath 來源圖片完整路徑
* @param string $destPath 目標儲存路徑
* @param int $degrees 旋轉角度(預設 90,順時針)
* @return bool 成功返回 true,失敗 false
*/
function rotateImage(string $srcPath, string $destPath, int $degrees = 90): bool
<?php
function rotateImage(string $srcPath, string $destPath, int $degrees = 90): bool
{
// 1. 讀取圖片資訊,判斷格式
$info = @getimagesize($srcPath);
if ($info === false) {
error_log("rotateImage: 無法讀取圖片 {$srcPath}");
return false;
}
// 2. 根據 MIME 類型建立 GD 資源
$createFunc = match ($info[2]) {
IMAGETYPE_GIF => 'imagecreatefromgif',
IMAGETYPE_JPEG => 'imagecreatefromjpeg',
IMAGETYPE_PNG => 'imagecreatefrompng',
IMAGETYPE_WEBP => 'imagecreatefromwebp',
default => null,
};
if ($createFunc === null) {
error_log("rotateImage: 不支援的圖片格式 {$info['mime']}");
return false;
}
$srcImg = $createFunc($srcPath);
if ($srcImg === false) {
error_log("rotateImage: GD 建立資源失敗 {$srcPath}");
return false;
}
// 3. 執行旋轉(背景色設為透明/白)
$bgColor = imagecolorallocatealpha($srcImg, 255, 255, 255, 127); // 透明白
$rotated = imagerotate($srcImg, $degrees, $bgColor);
if ($rotated === false) {
imagedestroy($srcImg);
error_log("rotateImage: imagerotate 失敗");
return false;
}
// 4. 另存為 JPEG(品質 90),可依需求改 PNG/WebP
$result = imagejpeg($rotated, $destPath, 90);
// 5. 釋放記憶體
imagedestroy($srcImg);
imagedestroy($rotated);
return $result;
}
// 使用範例
rotateImage('/var/www/uploads/photo.jpg', '/var/www/uploads/photo_rotated.jpg', 90);
?>
使用 getimagesize() 回傳的索引 2(IMAGETYPE_* 常量)判斷格式,比副檔名更可靠。支援 GIF/JPEG/PNG/WebP 四大主流格式。
imagerotate() 第三參數為旋轉後露出區域的填充色。使用 imagecolorallocatealpha() 設定 alpha=127(全透明),避免 PNG/WebP 出現黑邊;若輸出 JPEG,透明會自動轉白。
GD 資源佔用系統記憶體,**務必成對呼叫 imagedestroy() 釋放**,否則長時間運行的腳本(如批次處理)會導致記憶體洩漏、OOM Killer 介入。
@ 抑制 GD 函數警告,改由回傳值判斷error_log(),便於集中監控bool 而非拋出例外,適合工具型函數| 問題 | 原因 | 解決 |
|---|---|---|
| 旋轉後圖片變黑/有黑框 | 背景色預設黑色,透明通道處理不當 | 指定透明背景色 imagecolorallocatealpha(..., 127) |
| PNG 透明背景變黑 | 輸出 JPEG 不支援透明 | 輸出改用 imagepng() 或預先填白底 |
| 大圖旋轉記憶體爆炸 | GD 解碼後佔用寬×高×4 bytes | 分塊處理、增加 memory_limit、改用 Imagick |
| 旋轉角度非 90 倍數畫質差 | 雙線性插值導致模糊 | 僅允許 90/180/270 度,或啟用 imagesetinterpolation() |
| EXIF 方向標籤未處理 | 手機照片含 Orientation 標籤 | 上傳前用 exif_read_data() 讀取並自動旋轉 |
若專案已安裝 ImageMagick + php-imagick,建議改用:
$imagick = new Imagick($srcPath);
$imagick->rotateImage(new ImagickPixel('none'), $degrees); // none = 透明
$imagick->writeImage($destPath);
$imagick->destroy();
優勢:支援更多格式、自動處理 EXIF Orientation、大圖效能更好、API 更現代化。
PHP GD 旋轉圖片看似簡單,實則涉及格式偵測、透明度處理、記憶體管理、EXIF 相容等細節。封裝成可複用函數並加入完善錯誤處理,才能在生產環境穩定運行。