本文介紹一個功能極其豐富的 picture 類,整合了水印(文字/圖片)、縮放、裁剪、旋轉、翻轉、銳化、透明度調整、反色等核心圖片處理功能,採用「操作產生新圖、保留歷史」的設計思路,適合構建圖片編輯器、用戶頭像處理、水印批量加工等場景。
| 功能 | 核心方法 | 關鍵屬性 |
|---|---|---|
| 載入圖片 | 建構子 __construct() | $PICTURE_URL |
| 文字水印 | _mark_text() | $FONT_WORD, $FONT_SIZE, $FONT_COLOR, $FONT_PATH, $ANGLE |
| 圖片水印 | _mark_picture() | $FORCE_URL, $FORCE_X, $FORCE_Y |
| 縮放 | zoom() | $ZOOM, $ZOOM_MULTIPLE, $ZOOM_WIDTH, $ZOOM_HEIGHT |
| 裁剪 | cut() | $CUT_X, $CUT_Y, $CUT_WIDTH, $CUT_HEIGHT |
| 銳化 | sharp() | $SHARP |
| 透明度 | alpha_() | $ALPHA, $ALPHA_X, $ALPHA_Y |
| 任意角度旋轉 | turn() | $CIRCUMROTATE |
| 水平/垂直翻轉 | turn_x(), turn_y() | 無 |
| 反色 | return_color() | 無 |
| 輸出/保存 | show(), save_picture() | $DEST_URL |
<?php
class Picture {
private $srcImg; // 原圖資源
private $dstImg; // 處理後資源
private $info; // [width, height, mime, type]
public function __construct($path) {
$this->info = getimagesize($path);
if (!$this->info) throw new Exception("圖片不存在或格式不支援");
$this->srcImg = $this->createFromPath($path);
}
private function createFromPath($path) {
switch ($this->info[2]) {
case IMAGETYPE_GIF: return imagecreatefromgif($path);
case IMAGETYPE_JPEG: return imagecreatefromjpeg($path);
case IMAGETYPE_PNG: return imagecreatefrompng($path);
default: throw new Exception("不支援的圖片類型");
}
}
/** 縮放:支援倍數或固定寬高 */
public function zoom($scale = null, $width = null, $height = null) {
$srcW = $this->info[0]; $srcH = $this->info[1];
if ($scale) { $width = $srcW * $scale; $height = $srcH * $scale; }
if (!$width) $width = $srcW;
if (!$height) $height = $srcH;
$this->dstImg = imagecreatetruecolor($width, $height);
imagecopyresampled($this->dstImg, $this->srcImg, 0, 0, 0, 0, $width, $height, $srcW, $srcH);
$this->replaceSrc();
return $this;
}
/** 裁剪 */
public function crop($x, $y, $width, $height) {
$this->dstImg = imagecreatetruecolor($width, $height);
imagecopy($this->dstImg, $this->srcImg, 0, 0, $x, $y, $width, $height);
$this->replaceSrc();
return $this;
}
/** 文字水印 */
public function watermarkText($text, $fontPath, $fontSize = 20, $color = '#000000', $x = null, $y = null, $angle = 0) {
$this->dstImg = imagecreatetruecolor($this->info[0], $this->info[1]);
imagecopy($this->dstImg, $this->srcImg, 0, 0, 0, 0, $this->info[0], $this->info[1]);
$rgb = $this->hex2rgb($color);
$textColor = imagecolorallocate($this->dstImg, $rgb[0], $rgb[1], $rgb[2]);
$box = imagettfbbox($fontSize, $angle, $fontPath, $text);
$textW = $box[2] - $box[0];
$textH = $box[3] - $box[7];
$x = $x ?? $this->info[0] - $textW - 10;
$y = $y ?? $this->info[1] - $textH - 10;
imagettftext($this->dstImg, $fontSize, $angle, $x, $y, $textColor, $fontPath, $text);
$this->replaceSrc();
return $this;
}
/** 圖片水印 */
public function watermarkImage($waterPath, $x = 0, $y = 0, $opacity = 100) {
$waterInfo = getimagesize($waterPath);
$water = $this->createFromPath($waterPath);
$this->dstImg = imagecreatetruecolor($this->info[0], $this->info[1]);
imagecopy($this->dstImg, $this->srcImg, 0, 0, 0, 0, $this->info[0], $this->info[1]);
imagecopymerge($this->dstImg, $water, $x, $y, 0, 0, $waterInfo[0], $waterInfo[1], $opacity);
$this->replaceSrc();
return $this;
}
/** 旋轉 */
public function rotate($angle, $bgColor = '#FFFFFF') {
$rgb = $this->hex2rgb($bgColor);
$bg = imagecolorallocate($this->srcImg, $rgb[0], $rgb[1], $rgb[2]);
$this->dstImg = imagerotate($this->srcImg, $angle, $bg);
$this->replaceSrc();
return $this;
}
/** 銳化 */
public function sharpen($amount = 7) {
$this->dstImg = imagecreatetruecolor($this->info[0], $this->info[1]);
$kernel = [
[-1, -1, -1],
[-1, 16, -1],
[-1, -1, -1]
];
imageconvolution($this->srcImg, $kernel, $amount, 0);
$this->dstImg = $this->srcImg;
return $this;
}
/** 輸出顯示 */
public function output($quality = 90) {
header("Content-Type: {$this->info['mime']}");
switch ($this->info[2]) {
case IMAGETYPE_JPEG: imagejpeg($this->srcImg, null, $quality); break;
case IMAGETYPE_PNG: imagepng($this->srcImg); break;
case IMAGETYPE_GIF: imagegif($this->srcImg); break;
}
}
/** 保存文件 */
public function save($path, $quality = 90) {
switch ($this->info[2]) {
case IMAGETYPE_JPEG: imagejpeg($this->srcImg, $path, $quality); break;
case IMAGETYPE_PNG: imagepng($this->srcImg, $path); break;
case IMAGETYPE_GIF: imagegif($this->srcImg, $path); break;
}
}
private function replaceSrc() {
imagedestroy($this->srcImg);
$this->srcImg = $this->dstImg;
$this->info[0] = imagesx($this->srcImg);
$this->info[1] = imagesy($this->srcImg);
}
private function hex2rgb($hex) {
$hex = ltrim($hex, '#');
return [hexdec(substr($hex,0,2)), hexdec(substr($hex,2,2)), hexdec(substr($hex,4,2))];
}
public function __destruct() {
if ($this->srcImg) imagedestroy($this->srcImg);
if ($this->dstImg && $this->dstImg !== $this->srcImg) imagedestroy($this->dstImg);
}
}
<?php
require 'Picture.class.php';
$pic = new Picture('uploads/photo.jpg');
// 縮放 50% -> 加文字水印 -> 旋轉 15 度 -> 銳化 -> 保存
$pic->zoom(0.5)
->watermarkText('© MySite', 'fonts/msyh.ttc', 24, '#FF0000', 20, 20)
->rotate(15, '#F0F0F0')
->sharpen(5)
->save('output/photo_processed.jpg');
echo "處理完成!";
$this,支援流暢接口replaceSrc() 前將舊資源推入堆疊imagecopyresampled、imagerotate 中自動保留,需注意背景色設置imagettftext 能找到 TTF 文件getimagesize,失敗拋出異常filter() 支援濾鏡(灰階、模糊、浮雕)Intervention/Image 或 Imagine 以獲得更現代的 APIimagewebp)Picture::batch($files, $operations)這個類雖然代碼風格偏向 PHP 5 時代,但核心 GD 操作邏輯清晰、功能完整,經適當重構(命名空間、類型聲明、異常處理)即可投入現代項目使用,是理解 PHP 圖片處理底層原理的優秀教材。