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

PHP 圖片處理神類:縮圖、浮水印、裁切一站式解決方案 (Image Class)

     編輯:PHP 綜合知識

專案若需處理使用者上傳圖片(縮圖、加浮水印、裁切),從零撰寫 GD 庫邏輯既繁瑣又易出錯。本文提供一個**生產級 Image 類別**,封裝 thumb()、waterMark()、cut() 三大核心功能,支援 JPEG/PNG/GIF、透明度保留、等比縮放、9 種浮水印定位與隨機定位,開箱即用。

一、類別架構總覽

公開方法功能關鍵參數
thumb($name, $w, $h, $prefix='th_')等比縮放產生縮圖目標寬/高、輸出前綴
waterMark($ground, $water, $pos=0, $prefix='wa_')疊加圖片浮水印背景圖、水印圖、位置 0~9
cut($name, $x, $y, $w, $h, $prefix='cu_')裁切指定區域左上座標、寬高

內部私有方法處理:格式偵測(getInfo)、資源建立(getImg)、尺寸計算(getNewSize)、透明度保留(kidOfImage)、輸出儲存(createNewImage)、水印疊加(copyImage)、位置計算(position)。

二、核心程式碼 (image.class.php)

<?php
class Image {
    private $path;
    public function __construct(string $path = './') {
        $this->path = rtrim($path, '/') . '/';
    }

    // ========== 公開 API ==========
    public function thumb(string $name, int $width, int $height, string $prefix = 'th_') {
        $info   = $this->getInfo($name);
        $src    = $this->getImg($name, $info);
        $size   = $this->getNewSize($name, $width, $height, $info);
        $newImg = $this->kidOfImage($src, $size, $info);
        return $this->createNewImage($newImg, $prefix . $name, $info);
    }

    public function waterMark(string $ground, string $water, int $pos = 0, string $prefix = 'wa_') {
        $cur = rtrim($this->path, '/') . '/';
        $wdir = dirname($water);
        $wpath = ($wdir === '.') ? $cur : $wdir . '/';
        $water = basename($water);

        if (!file_exists($cur.$ground) || !file_exists($wpath.$water)) {
            trigger_error('圖片或水印檔案不存在', E_USER_WARNING);
            return false;
        }

        $gInfo = $this->getInfo($ground);
        $wInfo = $this->getInfo($water, $wdir);
        if (!$posArr = $this->position($gInfo, $wInfo, $pos)) {
            trigger_error('水印不應大於背景圖', E_USER_WARNING);
            return false;
        }

        $gImg = $this->getImg($ground, $gInfo);
        $wImg = $this->getImg($water, $wInfo, $wdir);
        $gImg = $this->copyImage($gImg, $wImg, $posArr, $wInfo);
        return $this->createNewImage($gImg, $prefix . $ground, $gInfo);
    }

    public function cut(string $name, int $x, int $y, int $w, int $h, string $prefix = 'cu_') {
        $info = $this->getInfo($name);
        if (($x+$w) > $info['width'] || ($y+$h) > $info['height']) {
            trigger_error('裁切區域超出圖片範圍', E_USER_WARNING);
            return false;
        }
        $src = $this->getImg($name, $info);
        $cut = imagecreatetruecolor($w, $h);
        imagecopyresampled($cut, $src, 0, 0, $x, $y, $w, $h, $w, $h);
        imagedestroy($src);
        return $this->createNewImage($cut, $prefix . $name, $info);
    }

    // ========== 私有輔助 ==========
    private function position(array $g, array $w, int $pos): ?array {
        if ($g['width'] < $w['width'] || $g['height'] < $w['height']) return null;
        $posMap = [
            1 => [0, 0],
            2 => [($g['width']-$w['width'])/2, 0],
            3 => [$g['width']-$w['width'], 0],
            4 => [0, ($g['height']-$w['height'])/2],
            5 => [($g['width']-$w['width'])/2, ($g['height']-$w['height'])/2],
            6 => [$g['width']-$w['width'], ($g['height']-$w['height'])/2],
            7 => [0, $g['height']-$w['height']],
            8 => [($g['width']-$w['width'])/2, $g['height']-$w['height']],
            9 => [$g['width']-$w['width'], $g['height']-$w['height']],
        ];
        if ($pos === 0) {
            return ['posX' => rand(0, $g['width']-$w['width']), 'posY' => rand(0, $g['height']-$w['height'])];
        }
        return ['posX' => $posMap[$pos][0] ?? 0, 'posY' => $posMap[$pos][1] ?? 0];
    }

    private function getInfo(string $name, string $path = '.'): array {
        $p = ($path === '.') ? $this->path : rtrim($path,'/').'/';
        $data = getimagesize($p.$name);
        return ['width'=>$data[0], 'height'=>$data[1], 'type'=>$data[2]];
    }

    private function getImg(string $name, array $info, string $path = '.') {
        $p = ($path === '.') ? $this->path : rtrim($path,'/').'/';
        return match($info['type']) {
            1 => imagecreatefromgif($p.$name),
            2 => imagecreatefromjpeg($p.$name),
            3 => imagecreatefrompng($p.$name),
            default => false
        };
    }

    private function getNewSize(string $name, int $w, int $h, array $info): array {
        $size = ['width'=>$info['width'], 'height'=>$info['height']];
        if ($w < $info['width'])  $size['width']  = $w;
        if ($h < $info['height']) $size['height'] = $h;
        // 等比縮放
        if ($info['width'] * $size['width'] > $info['height'] * $size['height']) {
            $size['height'] = round($info['height'] * $size['width'] / $info['width']);
        } else {
            $size['width'] = round($info['width'] * $size['height'] / $info['height']);
        }
        return $size;
    }

    private function kidOfImage($src, array $size, array $info) {
        $new = imagecreatetruecolor($size['width'], $size['height']);
        // 保留 GIF/PNG 透明度
        $transparent = imagecolortransparent($src);
        if ($transparent >= 0) {
            $rgb = imagecolorsforindex($src, $transparent);
            $newColor = imagecolorallocate($new, $rgb['red'], $rgb['green'], $rgb['blue']);
            imagefill($new, 0, 0, $newColor);
            imagecolortransparent($new, $newColor);
        }
        imagecopyresized($new, $src, 0,0,0,0, $size['width'],$size['height'], $info['width'],$info['height']);
        imagedestroy($src);
        return $new;
    }

    private function createNewImage($img, string $name, array $info): string {
        $this->path = rtrim($this->path,'/').'/';
        $result = match($info['type']) {
            1 => imagegif($img, $this->path.$name),
            2 => imagejpeg($img, $this->path.$name, 90),
            3 => imagepng($img, $this->path.$name),
            default => false
        };
        imagedestroy($img);
        return $result ? $name : false;
    }

    private function copyImage($ground, $water, array $pos, array $wInfo) {
        imagecopy($ground, $water, $pos['posX'], $pos['posY'], 0,0, $wInfo['width'], $wInfo['height']);
        imagedestroy($water);
        return $ground;
    }
}
?>

三、使用範例

require 'image.class.php';
$img = new Image('./uploads/');

// 1. 產生 300x200 縮圖
$thumb = $img->thumb('photo.jpg', 300, 200); // 產生 th_photo.jpg

// 2. 加浮水印(右下角=9)
$marked = $img->waterMark('photo.jpg', 'logo.png', 9); // 產生 wa_photo.jpg

// 3. 裁切 (100,100) 起 400x300 區域
$cropped = $img->cut('photo.jpg', 100, 100, 400, 300); // 產生 cu_photo.jpg

四、擴充建議與現代化替代

  • 介面化:實作 ImageProcessorInterface,方便未來切換至 Imagick 或 Intervention/Image。
  • 支援 WebP/AVIF:補充 imagecreatefromwebp、imagewebp、imageavif(PHP 8.1+)。
  • 文字浮水印:新增 textMark() 使用 imagettftext() 繪製文字。
  • 串流輸出:提供 output($format='jpeg', $quality=90) 直接輸出至瀏覽器而非落盤。
  • 例外處理:將 trigger_error 改拋出 ImageException,配合 try-catch 統一錯誤處理。

這個 Image 類別以精簡代碼涵蓋最常見的圖片處理需求,適合中小型專案快速整合;大型或高效能場景建議改用 Intervention/Image 或 Imagick 擴充套件。

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