首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 圖片智能裁剪:固定尺寸、不變形、無留白的完整實現

     編輯:PHP 綜合知識

場景痛點

首頁輪播圖、用戶頭像、商品縮略圖等場景常要求**固定寬高**。用戶上傳的圖片比例卻千差萬別,直接縮放會變形,等比縮放又會留白。理想方案:**圖片填滿目標框,多餘部分裁剪,不足部分智能拉伸,始終保持原圖比例不變形**。

算法核心邏輯

設原圖尺寸 ($w, $h),目標尺寸 ($new_w, $new_h)。計算寬高比:

$ratio_w = $new_w / $w;
$ratio_h = $new_h / $h;

分三種情況處理:

  1. 同向縮放/放大($ratio_w < 1 && $ratio_h < 1 或 > 1):
    取**較大比例** $ratio = max($ratio_w, $ratio_h),先按此比例縮放/放大原圖生成中間圖,中間圖的寬高比已與目標一致,再等比縮放至目標尺寸。
  2. 一放一縮($ratio_w < 1 && $ratio_h > 1 或相反):
    取**較大比例** $ratio = max($ratio_w, $ratio_h),先放大原圖使短邊達到目標,長邊超出,再從中間裁剪目標尺寸。
  3. 邊界情況:任一比例等於 1,歸入上述邏輯統一處理。

完整 PHP 實現

<?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);

關鍵點補充

  • 透明度保持:PNG/GIF 需在創建真彩色圖前啟用 imagesavealpha($img, true) 並分配透明色。
  • 大圖性能:超大圖建議分塊處理或使用 ImageMagick (Imagick 擴展),GD 受限於內存限制。
  • 裁剪錨點:代碼採用**居中裁剪**,亦可擴展參數支持頂部、底部、臉部識別裁剪。
  • 錯誤處理:生產環境建議捕獲異常並記錄日誌,返回統一錯誤碼。

總結

通過「先調整比例、再裁剪/縮放」兩步走策略,配合 GD 庫的 imagecopy(無縮放裁剪)與 imagecopyresampled(高質量縮放),即可實現任意比例源圖到固定尺寸的完美適配。封裝為工具函數或類,即可在上傳處理、縮圖生成等場景複用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved