在 PHP 開發中,圖片處理是常見需求,例如加浮水印、生成縮圖、固定寬高裁切等。本文分享兩個實用的 PHP 圖片處理類,分別展示基本的水印疊加、等比縮放、固定尺寸縮略圖,以及更進階的裁切壓縮、多格式支援與目錄自動建立功能。
這個類別封裝了常用的圖片處理邏輯,支援 GIF、JPG、PNG 三種格式。主要功能包括:
waterMakeImage():將 Logo 置中疊加為水印fixSizeImage():依指定寬高裁切(若超過原圖則保持原尺寸)scaleImage():依比例縮放tinyImage():核心縮圖邏輯,優先使用 imagecopyresampled 取得較佳品質saveImage():統一輸出為 JPEG 格式<?php
class Image_process {
public $source;
public $source_width;
public $source_height;
public $source_type_id;
public $orign_name;
public $orign_dirname;
private $typeList = array(1=>'gif', 2=>'jpg', 3=>'png');
public function __construct($source) {
$ginfo = getimagesize($source);
$this->source_width = $ginfo[0];
$this->source_height = $ginfo[1];
$this->source_type_id = $ginfo[2];
$this->orign_url = $source;
$this->orign_name = basename($source);
$this->orign_dirname = dirname($source);
}
private function judgeType($type, $source) {
switch ($type) {
case 1: return imagecreatefromgif($source);
case 2: return imagecreatefromjpeg($source);
case 3: return imagecreatefrompng($source);
default: return false;
}
}
public function waterMakeImage($logo) {
$linfo = getimagesize($logo);
$logo_w = $linfo[0]; $logo_h = $linfo[1]; $logo_type = $linfo[2];
$src = $this->judgeType($this->source_type_id, $this->orign_url);
$logoRes = $this->judgeType($logo_type, $logo);
if (!$src || !$logoRes) return false;
$x = ($this->source_width - $logo_w) / 2;
$y = ($this->source_height - $logo_h) / 2;
imagecopy($src, $logoRes, $x, $y, 0, 0, $logo_w, $logo_h);
$newPic = $this->orign_dirname . '/water_' . time() . '.' . $this->typeList[$this->source_type_id];
if ($this->saveImage($src, $newPic)) {
imagedestroy($src); imagedestroy($logoRes);
}
}
public function fixSizeImage($width, $height) {
if ($width > $this->source_width) $width = $this->source_width;
if ($height > $this->source_height) $height = $this->source_height;
if ($width === false) $width = floor($this->source_width / ($this->source_height / $height));
if ($height === false) $height = floor($this->source_height / ($this->source_width / $width));
$this->tinyImage($width, $height);
}
public function scaleImage($scale) {
$w = floor($this->source_width * $scale);
$h = floor($this->source_height * $scale);
$this->tinyImage($w, $h);
}
private function tinyImage($width, $height) {
$thumb = imagecreatetruecolor($width, $height);
$src = $this->judgeType($this->source_type_id, $this->orign_url);
if (function_exists('imagecopyresampled')) {
imagecopyresampled($thumb, $src, 0,0,0,0, $width,$height, $this->source_width,$this->source_height);
} else {
imagecopyresized($thumb, $src, 0,0,0,0, $width,$height, $this->source_width,$this->source_height);
}
$newPic = $this->orign_dirname . '/thumb_' . time() . '_' . $width . '_' . $height . '.' . $this->typeList[$this->source_type_id];
if ($this->saveImage($thumb, $newPic)) {
imagedestroy($thumb); imagedestroy($src);
}
}
private function saveImage($image, $url) {
return imagejpeg($image, $url);
}
}
// 使用範例
$img = new Image_process('D:/AppServ/www/test/getimg/14061907445601.jpg');
// $img->waterMakeImage('D:/AppServ/www/test/getimg/shougongke.png'); // 加水印
// $img->fixSizeImage(200, 150); // 固定尺寸
$img->scaleImage(0.2); // 等比縮放 20%
?>
第二個類別 Img 功能更完整,包含:
thumb_img():先裁切再等比縮放,避免圖片變形resize_image():單純等比縮放,支援只限寬或只限高water_mark():水印位置、透明度可配置check_dir():儲存路徑不存在時自動建立目錄array('flag'=>bool, 'msg'=>string)<?php
class Img {
private $exts = array('jpg','jpeg','gif','bmp','png');
public function __construct() {
if (!function_exists('gd_info')) throw new Exception('GD庫未載入!');
}
// 裁切壓縮:保持比例裁切後再縮放至目標尺寸
public function thumb_img($src_img, $save_img='', $option) {
if (empty($option['width']) || empty($option['height'])) return array('flag'=>false,'msg'=> '尺寸不可為0');
$org = $this->is_img($src_img); if (!$org['flag']) return $org;
if ($save_img) { $chk = $this->check_dir($save_img); if (!$chk['flag']) return $chk; }
$funcs = $this->get_img_funcs($org['msg']);
$src = $funcs['create_func']($src_img);
$sw = imagesx($src); $sh = imagesy($src);
$dst_scale = $option['height'] / $option['width'];
$src_scale = $sh / $sw;
if ($src_scale >= $dst_scale) { // 過高
$w = $sw; $h = intval($dst_scale * $w);
$x = 0; $y = ($sh - $h) / 3;
} else { // 過寬
$h = $sh; $w = intval($h / $dst_scale);
$x = ($sw - $w) / 2; $y = 0;
}
$crop = imagecreatetruecolor($w, $h);
imagecopy($crop, $src, 0,0, $x,$y, $sw,$sh);
$scale = $option['width'] / $w;
$target = imagecreatetruecolor($option['width'], $option['height']);
$fw = intval($w * $scale); $fh = intval($h * $scale);
imagecopyresampled($target, $crop, 0,0,0,0, $fw,$fh, $w,$h);
imagedestroy($crop);
if ($save_img) $funcs['save_func']($target, $save_img);
else { header($funcs['header']); $funcs['save_func']($target); }
imagedestroy($target);
return array('flag'=>true,'msg'=>'');
}
// 等比縮放(不裁切)
public function resize_image($src_img, $save_img='', $option) {
$org = $this->is_img($src_img); if (!$org['flag']) return $org;
if ($save_img) { $chk = $this->check_dir($save_img); if (!$chk['flag']) return $chk; }
$funcs = $this->get_img_funcs($org['msg']);
$src = $funcs['create_func']($src_img);
$sw = imagesx($src); $sh = imagesy($src);
$ratio = 1;
if (($option['width'] && $sw > $option['width']) || ($option['height'] && $sh > $option['height'])) {
if ($option['width'] && $sw > $option['width']) $ratio = $option['width'] / $sw;
if ($option['height'] && $sh > $option['height']) $ratio = min($ratio, $option['height'] / $sh);
$nw = $sw * $ratio; $nh = $sh * $ratio;
if (function_exists('imagecopyresampled')) {
$new = imagecreatetruecolor($nw,$nh);
imagecopyresampled($new,$src,0,0,0,0,$nw,$nh,$sw,$sh);
} else {
$new = imagecreate($nw,$nh);
imagecopyresized($new,$src,0,0,0,0,$nw,$nh,$sw,$sh);
}
} else { $new = $src; }
if ($save_img) $funcs['save_func']($new,$save_img);
else { header($funcs['header']); $funcs['save_func']($new); }
imagedestroy($new);
return array('flag'=>true,'msg'=>'');
}
// 水印:支援位置(x,y)與透明度(alpha)
public function water_mark($org_img, $mark_img, $save_img='', $option=array()) {
$org = $this->is_img($org_img); if (!$org['flag']) return $org;
$mark = $this->is_img($mark_img); if (!$mark['flag']) return $mark;
if ($save_img) { $chk = $this->check_dir($save_img); if (!$chk['flag']) return $chk; }
$of = $this->get_img_funcs($org['msg']);
$mf = $this->get_img_funcs($mark['msg']);
$oim = $of['create_func']($org_img);
$mim = $mf['create_func']($mark_img);
$ow = imagesx($oim); $oh = imagesy($oim);
$mw = imagesx($mim); $mh = imagesy($mim);
$x = isset($option['x']) ? $option['x'] : $ow - $mw;
$y = isset($option['y']) ? $option['y'] : $oh - $mh;
$x = ($x > $ow || $x < 0) ? $ow-$mw : $x;
$y = ($y > $oh || $y < 0) ? $oh-$mh : $y;
$alpha = isset($option['alpha']) ? $option['alpha'] : 50;
$alpha = ($alpha > 100 || $alpha < 0) ? 50 : $alpha;
imagecopymerge($oim, $mim, $x, $y, 0, 0, $mw, $mh, $alpha);
if ($save_img) $of['save_func']($oim,$save_img);
else { header($of['header']); $of['save_func']($oim); }
imagedestroy($oim); imagedestroy($mim);
return array('flag'=>true,'msg'=>'');
}
private function is_img($path) {
if (!file_exists($path)) return array('flag'=>false,'msg'=>"找不到檔案:$path");
$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
if (!in_array($ext, $this->exts)) return array('flag'=>false,'msg'=>"不支援的格式:$ext");
return array('flag'=>true,'msg'=>$ext);
}
private function get_img_funcs($ext) {
switch ($ext) {
case 'jpg': case 'jpeg': return array('header'=>'Content-Type:image/jpeg','create_func'=>'imagecreatefromjpeg','save_func'=>'imagejpeg');
case 'gif': return array('header'=>'Content-Type:image/gif','create_func'=>'imagecreatefromgif','save_func'=>'imagegif');
case 'bmp': return array('header'=>'Content-Type:image/bmp','create_func'=>'imagecreatefrombmp','save_func'=>'imagebmp');
default: return array('header'=>'Content-Type:image/png','create_func'=>'imagecreatefrompng','save_func'=>'imagepng');
}
}
private function check_dir($path) {
$dir = dirname($path);
if (!is_dir($dir) && !mkdir($dir, 0777, true)) return array('flag'=>false,'msg'=>"無法建立目錄:$dir");
return array('flag'=>true,'msg'=>'');
}
}
?>
Image_process,程式碼輕量易懂。Img 類別。