首頁輪播圖、用戶頭像、商品縮略圖等場景常要求**固定寬高**。用戶上傳的圖片比例卻千差萬別,直接縮放會變形,等比縮放又會留白。理想方案:**圖片填滿目標框,多餘部分裁剪,不足部分智能拉伸,始終保持原圖比例不變形**。
設原圖尺寸 ($w, $h),目標尺寸 ($new_w, $new_h)。計算寬高比:
$ratio_w = $new_w / $w;
$ratio_h = $new_h / $h;
分三種情況處理:
$ratio_w < 1 && $ratio_h < 1 或 > 1):$ratio = max($ratio_w, $ratio_h),先按此比例縮放/放大原圖生成中間圖,中間圖的寬高比已與目標一致,再等比縮放至目標尺寸。$ratio_w < 1 && $ratio_h > 1 或相反):$ratio = max($ratio_w, $ratio_h),先放大原圖使短邊達到目標,長邊超出,再從中間裁剪目標尺寸。<?php
/**
* 智能裁剪圖片至固定尺寸
* @param string $src_file 源圖路徑
* @param string $dst_file 目標路徑
* @param int $new_width 目標寬度
* @param int $new_height 目標高度
* @return bool
*/
function smart_resize($src_file, $dst_file, $new_width, $new_height) {
// 參數校驗
if ($new_width < 1 || $new_height < 1) throw new InvalidArgumentException('尺寸無效');
if (!file_exists($src_file)) throw new RuntimeException('源文件不存在');
// 檢測圖片類型
$type = exif_imagetype($src_file);
$support = [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF];
if (!in_array($type, $support, true)) throw new RuntimeException('僅支持 JPG/PNG/GIF');
// 載入圖片資源
$create_from = [
IMAGETYPE_JPEG => 'imagecreatefromjpeg',
IMAGETYPE_PNG => 'imagecreatefrompng',
IMAGETYPE_GIF => 'imagecreatefromgif',
];
$src_img = $create_from[$type]($src_file);
$w = imagesx($src_img);
$h = imagesy($src_img);
$ratio_w = $new_width / $w;
$ratio_h = $new_height / $h;
// 情況 1:同向縮放/放大
if (($ratio_w < 1 && $ratio_h < 1) || ($ratio_w > 1 && $ratio_h > 1)) {
$ratio = max($ratio_w, $ratio_h);
$inter_w = (int)($new_width / $ratio);
$inter_h = (int)($new_height / $ratio);
$inter_img = imagecreatetruecolor($inter_w, $inter_h);
imagecopy($inter_img, $src_img, 0, 0, 0, 0, $inter_w, $inter_h); // 裁剪中間區域
$new_img = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($new_img, $inter_img, 0, 0, 0, 0, $new_width, $new_height, $inter_w, $inter_h);
}
// 情況 2:一放一縮
else {
$ratio = max($ratio_w, $ratio_h);
$inter_w = (int)($w * $ratio);
$inter_h = (int)($h * $ratio);
$inter_img = imagecreatetruecolor($inter_w, $inter_h);
imagecopyresampled($inter_img, $src_img, 0, 0, 0, 0, $inter_w, $inter_h, $w, $h); // 放大/縮小
$new_img = imagecreatetruecolor($new_width, $new_height);
// 從中間裁剪目標尺寸
$src_x = ($inter_w - $new_width) / 2;
$src_y = ($inter_h - $new_height) / 2;
imagecopy($new_img, $inter_img, 0, 0, $src_x, $src_y, $new_width, $new_height);
}
// 輸出保存
$save_func = [
IMAGETYPE_JPEG => fn($img, $file) => imagejpeg($img, $file, 90),
IMAGETYPE_PNG => fn($img, $file) => imagepng($img, $file, 9),
IMAGETYPE_GIF => fn($img, $file) => imagegif($img, $file),
];
$save_func[$type]($new_img, $dst_file);
// 釋放資源
imagedestroy($src_img);
imagedestroy($inter_img);
imagedestroy($new_img);
return true;
}
// 使用示例
smart_resize('upload/photo.jpg', 'thumb/photo_300x200.jpg', 300, 200);
imagesavealpha($img, true) 並分配透明色。通過「先調整比例、再裁剪/縮放」兩步走策略,配合 GD 庫的 imagecopy(無縮放裁剪)與 imagecopyresampled(高質量縮放),即可實現任意比例源圖到固定尺寸的完美適配。封裝為工具函數或類,即可在上傳處理、縮圖生成等場景複用。