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

PHP 圖像處理類庫實戰分享:驗證碼、縮圖、文字繪製與 GD 封裝完整代碼

     編輯:PHP 相關知識

自建 PHP 圖像處理類庫:驗證碼生成、縮圖裁切、文字繪製、GD 封裝一站式方案

專案中頻繁需要驗證碼、縮圖、動態文字圖片,與其每次重寫 GD 代碼,不如封裝可復用的 Img 類別。本文提供完整類別代碼(支援鏈式調用)、使用範例、擴充建議與常見坑點。

Img 類別完整代碼

<?php
if (!defined('__WEBROOT__')) define('__WEBROOT__', $_SERVER['DOCUMENT_ROOT']);

class Img {
  protected $_img;       // 目標圖像資源
  protected $_srcImg;    // 來源圖像資源
  protected $_srcInfo;   // 來源圖像資訊 [width, height, type, ...]
  protected $_rand = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789';
  protected $_code = ''; // 驗證碼明文

  // 公開屬性(可由 Style() 覆寫)
  public $width = 100;
  public $height = 30;
  public $backgroundColor = '000000';
  public $font = '/fonts/ARIALNB.TTF';
  public $fontSize = 16;
  public $fontColor = 'ffffff';
  public $content = 'Test';
  public $align = 'left';
  public $codes = 4;      // 驗證碼字元數
  public $lines = 6;      // 干擾線條數
  public $loadErr = '';

  /** 設定樣式(鏈式) */
  public function Style(array $opts) {
    $this->_reset();
    foreach ($opts as $k => $v) {
      if (property_exists($this, $k)) {
        if (in_array($k, ['backgroundColor','fontColor'])) {
          if (preg_match('/^[a-fA-F0-9]{6}$/', $v)) $this->$k = $v;
        } else {
          $this->$k = $v;
        }
      }
    }
    return $this;
  }

  protected function _reset() {
    $this->width = 100; $this->height = 30;
    $this->backgroundColor = '000000'; $this->fontSize = 16;
    $this->fontColor = 'ffffff'; $this->align = 'left';
    $this->codes = 4; $this->lines = 6;
  }

  /** 建立真彩畫布、填充背景 */
  protected function _createCanvas($fillBg = true) {
    $this->_img = imagecreatetruecolor($this->width, $this->height);
    if ($fillBg) {
      $c = $this->_hex2rgb($this->backgroundColor);
      $bg = imagecolorallocate($this->_img, $c[0], $c[1], $c[2]);
      imagefilledrectangle($this->_img, 0, 0, $this->width, $this->height, $bg);
    }
  }

  protected function _hex2rgb($hex) {
    return [hexdec(substr($hex,0,2)), hexdec(substr($hex,2,2)), hexdec(substr($hex,4,2))];
  }

  /** 輸出 PNG */
  protected function _outputPng() {
    header('Content-Type: image/png');
    imagepng($this->_img);
    imagedestroy($this->_img);
  }
  /** 輸出 JPEG */
  protected function _outputJpeg() {
    header('Content-Type: image/jpeg');
    imagejpeg($this->_img, null, 90);
    imagedestroy($this->_img);
  }

  /** 公開:建立文字圖片 (PNG) */
  public function CreateImgPng() {
    $this->_createCanvas();
    $this->_writeText();
    $this->_outputPng();
  }
  /** 公開:建立文字圖片 (JPEG) */
  public function CreateImgJpeg() {
    $this->_createCanvas();
    $this->_writeText();
    $this->_outputJpeg();
  }

  protected function _writeText() {
    $box = imagettfbbox($this->fontSize, 0, __WEBROOT__.$this->font, $this->content);
    $textW = $box[2] - $box[0];
    $textH = $box[1] - $box[7];
    $x = ($this->width - $textW) / 2;
    $y = ($this->height + $textH) / 2;
    $c = $this->_hex2rgb($this->fontColor);
    $color = imagecolorallocate($this->_img, $c[0], $c[1], $c[2]);
    imagettftext($this->_img, $this->fontSize, 0, $x, $y, $color, __WEBROOT__.$this->font, $this->content);
  }

  /** 公開:建立驗證碼圖片 */
  public function CreateVerify() {
    $this->backgroundColor = '';
    for ($i=0;$i<3;$i++) $this->backgroundColor .= dechex(mt_rand(20,155));
    $this->_createCanvas();
    $this->_genCode();
    $this->_drawLines();
    $this->_writeCode();
    $this->_outputPng();
  }

  protected function _genCode() {
    $len = strlen($this->_rand) - 1;
    for ($i=0;$i<$this->codes;$i++) $this->_code .= $this->_rand[mt_rand(0,$len)];
  }

  protected function _drawLines() {
    for ($i=0;$i<$this->lines;$i++) {
      $c = imagecolorallocate($this->_img, mt_rand(0,156), mt_rand(0,156), mt_rand(0,156));
      imageline($this->_img, mt_rand(0,$this->width), mt_rand(0,$this->height),
                mt_rand(0,$this->width), mt_rand(0,$this->height), $c);
    }
  }

  protected function _writeCode() {
    $charW = $this->width / $this->codes;
    for ($i=0;$i<$this->codes;$i++) {
      $c = imagecolorallocate($this->_img, mt_rand(0,156), mt_rand(0,156), mt_rand(0,156));
      imagettftext($this->_img, $this->fontSize, mt_rand(-30,30),
        $charW*$i + mt_rand(1,5), $this->height/1.3, $c,
        __WEBROOT__.$this->font, $this->_code[$i]);
    }
  }

  /** 取得驗證碼 MD5(儲存 Session 比對) */
  public function GetVerify() { return md5($this->_code); }

  /** 載入來源圖片 */
  public function LoadImg($relPath) {
    $abs = __WEBROOT__.$relPath;
    if (!is_file($abs)) { $this->loadErr = '檔案不存在'; return false; }
    $this->_srcInfo = getimagesize($abs);
    $this->_srcInfo['path'] = $abs;
    switch ($this->_srcInfo[2]) {
      case IMAGETYPE_GIF:  $this->_srcImg = imagecreatefromgif($abs); break;
      case IMAGETYPE_JPEG: $this->_srcImg = imagecreatefromjpeg($abs); break;
      case IMAGETYPE_PNG:  $this->_srcImg = imagecreatefrompng($abs); break;
      default: $this->loadErr = '不支援格式'; return false;
    }
    return true;
  }

  /** 建立縮圖並儲存 */
  public function CreateThumb($prefix, $saveRelDir) {
    if (!$this->_srcImg) return false;
    $saveAbsDir = __WEBROOT__.$saveRelDir;
    if (!is_dir($saveAbsDir)) mkdir($saveAbsDir, 0777, true);
    $ext = image_type_to_extension($this->_srcInfo[2], false);
    $filename = $prefix . date('YmdHis') . mt_rand(100,999) . '.' . $ext;
    $savePath = $saveAbsDir . $filename;
    $this->_createCanvas(false);
    imagecopyresampled($this->_img, $this->_srcImg,
      0,0,0,0, $this->width, $this->height,
      $this->_srcInfo[0], $this->_srcInfo[1]);
    switch ($this->_srcInfo[2]) {
      case IMAGETYPE_GIF:  imagegif($this->_img, $savePath); break;
      case IMAGETYPE_JPEG: imagejpeg($this->_img, $savePath, 90); break;
      case IMAGETYPE_PNG:  imagepng($this->_img, $savePath); break;
    }
    imagedestroy($this->_img);
    return ['filename'=>$filename, 'path'=>$saveRelDir.$filename];
  }
}

使用範例

<?php
require 'Img.php';
$img = new Img();

// 1. 產生文字圖片
$img->Style([
  'width'=>300, 'height'=>100,
  'content'=>'Hello PHP',
  'fontColor'=>'FF0000',
  'backgroundColor'=>'EEEEEE'
])->CreateImgPng();

// 2. 產生驗證碼並存 Session
session_start();
$img->Style(['width'=>120,'height'=>40,'codes'=>4,'lines'=>8])->CreateVerify();
$_SESSION['captcha'] = $img->GetVerify();

// 3. 縮圖
if ($img->LoadImg('/uploads/photo.jpg')) {
  $info = $img->Style(['width'=>200,'height'=>200])->CreateThumb('thumb_', '/uploads/thumbs/');
  var_dump($info); // ['filename'=>'thumb_20240115123045_123.jpg', 'path'=>'/uploads/thumbs/thumb_...']
} else {
  die('載入失敗: '.$img->loadErr);
}

擴充建議

  • 加入水印方法:imagecopy() 疊加 Logo/文字
  • 支援圓角、圓形裁切:imagefilledarc() 建立遮罩
  • 整合 Intervention/Image 或 Imagick 作為後端,自動切換 GD/Imagick
  • 加入Base64 輸出模式:ob_start(); imagepng($img); $b64 = base64_encode(ob_get_clean()); 供 API 直接回傳 JSON

常見坑點

  1. 字體路徑 __WEBROOT__.$this->font 必須為**絕對路徑**,相對路徑在 CLI/不同工作目錄下失效。
  2. imagecreatetruecolor 需 GD 2.0+,舊版主機確認支援。
  3. 輸出圖片前**不可有任何輸出**(含 BOM、空白、echo),否則圖片損壞。
  4. 大量併發生成驗證碼會佔用 CPU,建議快取字體路徑、預生成驗證碼圖片池。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved