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

PHP 圖片上傳與裁剪實戰:基於 CodeIgniter/GD2 的等比縮放+居中裁剪生成方形縮圖

     編輯:PHP 相關知識

從上傳到完美方形縮圖:等比縮放 + 智能裁剪完整流程

頭像、商品封面、文章配圖常需統一規格(如 180×180px)。本文展示基於 CodeIgniter 3 + GD2 庫的完整實現:上傳驗證 → 等比縮放至目標邊長 → 居中裁剪多餘區域 → 輸出高質量縮圖。

控制器完整代碼

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Media extends CI_Controller {
    public function __construct() {
        parent::__construct();
        $this->load->helper(['form', 'url']);
    }

    public function upload_avatar() {
        // 1. 上傳配置
        $config = [
            'upload_path'   => './data/uploads/',
            'allowed_types' => 'gif|jpg|png',
            'max_size'      => 2048,      // 2MB
            'max_width'     => 2048,
            'max_height'    => 2048,
            'encrypt_name'  => true,      // 防重名
        ];
        $this->load->library('upload', $config);

        if (!$this->upload->do_upload('avatar')) {
            return $this->output
                ->set_status(400)
                ->set_json(['error' => $this->upload->display_errors()]);
        }

        $data = $this->upload->data(); // 含 full_path, file_name, image_width, image_height
        $src = $data['full_path'];
        list($w, $h) = [$data['image_width'], $data['image_height']];

        // 2. 等比縮放:短邊縮放至 180px
        $target = 180;
        $this->load->library('image_lib');
        $cfg = [
            'image_library' => 'gd2',
            'source_image'  => $src,
            'maintain_ratio'=> TRUE,
            'master_dim'    => ($w >= $h) ? 'height' : 'width', // 短邊為基準
            'width'         => $target,
            'height'        => $target,
            'quality'       => 90,
        ];
        $this->image_lib->initialize($cfg);
        if (!$this->image_lib->resize()) {
            return $this->output->set_status(500)->set_json(['error' => $this->image_lib->display_errors()]);
        }

        // 3. 居中裁剪:長邊超出部分兩側各切一半
        $this->image_lib->clear();
        $cfg['maintain_ratio'] = FALSE;
        if ($w >= $h) {
            // 橫圖:寬 > 高,裁剪左右
            $newW = round($w * $target / $h);
            $cfg['x_axis'] = floor(($newW - $target) / 2);
            $cfg['y_axis'] = 0;
        } else {
            // 縱圖:高 > 寬,裁剪上下
            $newH = round($h * $target / $w);
            $cfg['x_axis'] = 0;
            $cfg['y_axis'] = floor(($newH - $target) / 2);
        }
        $this->image_lib->initialize($cfg);
        if (!$this->image_lib->crop()) {
            return $this->output->set_status(500)->set_json(['error' => $this->image_lib->display_errors()]);
        }

        // 4. 返回結果
        $url = base_url('data/uploads/' . $data['file_name']);
        $this->output->set_json(['url' => $url, 'width' => $target, 'height' => $target]);
    }
}

關鍵參數解析

參數含義本例取值
master_dim基準維度:width/height/auto短邊優先,保證長邊 ≥ 目標尺寸
maintain_ratioTRUE=等比縮放,FALSE=強制尺寸(裁剪時用)兩階段切換
x_axis/y_axis裁剪起始座標(左上角為 0,0)居中計算:floor((長邊-目標)/2)
qualityJPEG 輸出質量 0-10090(平衡體積/清晰度)

原生 GD 實現(無框架依賴)

function makeSquareThumb(string $srcPath, string $destPath, int $size = 180, int $quality = 90): bool {
    list($w, $h, $type) = getimagesize($srcPath);
    $create = match($type) {
        IMAGETYPE_JPEG => 'imagecreatefromjpeg',
        IMAGETYPE_PNG  => 'imagecreatefrompng',
        IMAGETYPE_GIF  => 'imagecreatefromgif',
        default => throw new Exception('Unsupported type'),
    };
    $srcImg = $create($srcPath);

    // 透明背景處理 (PNG/GIF)
    if ($type !== IMAGETYPE_JPEG) {
        imagealphablending($srcImg, false);
        imagesavealpha($srcImg, true);
    }

    // 目標畫布
    $thumb = imagecreatetruecolor($size, $size);
    if ($type !== IMAGETYPE_JPEG) {
        imagealphablending($thumb, false);
        imagesavealpha($thumb, true);
        $transparent = imagecolorallocatealpha($thumb, 0,0,0,127);
        imagefill($thumb, 0, 0, $transparent);
    } else {
        $white = imagecolorallocate($thumb, 255,255,255);
        imagefill($thumb, 0, 0, $white);
    }

    // 計算縮放比例與裁剪區域
    if ($w >= $h) {
        $newW = round($w * $size / $h);
        $srcX = floor(($newW - $size) / 2);
        $srcY = 0;
        $srcW = $size; $srcH = $size;
        $dstW = $newW; $dstH = $size;
    } else {
        $newH = round($h * $size / $w);
        $srcX = 0;
        $srcY = floor(($newH - $size) / 2);
        $srcW = $size; $srcH = $size;
        $dstW = $size; $dstH = $newH;
    }

    // 先縮放到臨時畫布
    $temp = imagecreatetruecolor($dstW, $dstH);
    imagecopyresampled($temp, $srcImg, 0,0, 0,0, $dstW, $dstH, $w, $h);

    // 再從臨時畫布居中裁剪到最終畫布
    imagecopyresampled($thumb, $temp, 0,0, $srcX, $srcY, $size, $size, $size, $size);

    // 輸出
    $out = match($type) {
        IMAGETYPE_JPEG => fn() => imagejpeg($thumb, $destPath, $quality),
        IMAGETYPE_PNG  => fn() => imagepng($thumb, $destPath, 9),
        IMAGETYPE_GIF  => fn() => imagegif($thumb, $destPath),
    };
    $ok = $out();
    imagedestroy($srcImg); imagedestroy($temp); imagedestroy($thumb);
    return $ok;
}

生產環境建議

  • 大圖處理:ini_set('memory_limit', '256M'),或分塊處理(Imagick 支援流式)。
  • 格式轉換:統一輸出 WebP (imagewebp) 節省 30%+ 體積。
  • 異步隊列:上傳即返回,縮圖生成推入 Redis/RabbitMQ,Worker 消費。
  • CDN 回源:原圖存 OSS,縮圖按需生成(圖片服務/Cloudinary/阿里云圖片處理)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved