| 功能 | 實現關鍵點 |
| 多形狀選區 | 狀態機 mode (1=矩形, 2=圓形, 3=圓角矩形, 4=圓弧, 5=多邊形, 6=任意)。Canvas 繪製路徑 (rect, arc, bezierCurveTo, lineTo)。 |
| 拖拽/縮放選區 | 鼠標事件 (mousedown/move/up) 判斷點擊區域 (邊緣/內部/控制點) → 更新幾何參數 (x,y,w,h,radius,angles) → 重繪。 |
| 鍵盤微調 | keydown/keyup 監聽方向鍵 (移動)、J/K/L/M (縮放)、A/D (圓角)、W/A/S/D (圓弧弧度)、Shift 鎖定比例。 |
| 動圖支持 | 上傳響應返回 frameCount,前端預留幀處理邏輯 (演示版未完全實現)。 |
| 跨瀏覽器 Canvas | IE < 9 使用 excanvas.js (VML 模擬);現代瀏覽器原生 getContext('2d')。 |
| 漸變標題欄 | createLinearGradient 繪製標題背景,提升 UI 質感。 |
3. 關鍵數據結構
var imgData = {
url: 'upload/20230101120000123.jpg', // 服務端返回的文件路徑
width: 800, // 顯示寬度 (限制最大 800px)
height: 600, // 等比縮放高度
frames: 1, // 幀數
size: 102400 // 文件大小
};
var selection = {
shape: 1, // 當前形狀類型
x: 100, y: 100, // 左上角
w: 200, h: 150, // 寬高
radius: 10, // 圓角半徑
startAngle: 0, // 圓弧起始角度
endAngle: 270, // 圓弧結束角度
points: [], // 多邊形/任意形狀頂點
inout: 0, // 0=裁剪內部, 1=裁剪外部
transparent: 1 // 1=透明背景, 0=白色背景
};
後端處理流程 (upload.php)
<?php
// 安全校驗:防止跨站調用
if (stripos($_SERVER['HTTP_HOST'], 'caijian.cc') === false) exit(0);
// 文件類型與大小驗證 (3MB 限制)
$allowedTypes = ['image/gif', 'image/jpeg', 'image/pjpeg', 'image/bmp', 'image/png'];
$maxSize = 3000000;
if (in_array($_FILES['ifile']['type'], $allowedTypes) && $_FILES['ifile']['size'] < $maxSize) {
if ($_FILES['ifile']['error'] > 0) {
echo "<script>parent.wrong('上傳錯誤: " . $_FILES['ifile']['error'] . "');</script>";
} else {
// 生成唯一文件名
$ext = substr($_FILES['ifile']['name'], strrpos($_FILES['ifile']['name'], '.'));
$filename = "upload/" . date("YmdHis") . rand(100, 999) . $ext;
// 移動文件
move_uploaded_file($_FILES['ifile']['tmp_name'], $filename);
// ImageMagick 提取元數據
$wand = NewMagickWand();
MagickReadImage($wand, $filename);
$w = MagickGetImageWidth($wand);
$h = MagickGetImageHeight($wand);
$f = MagickGetNumberImages($wand); // GIF 幀數
// 返回 JS 回調初始化前端
echo "<script>parent.upimg('$filename', {$_FILES['ifile']['size']}, $w, $h, $f);</script>";
}
} else {
echo "<script>parent.wrong('文件類型不支持或超過 3MB');</script>";
}
?>
裁剪執行端 (未展示代碼,邏輯推測)
前端發送裁剪參數 (region, imgdata, back, inout, toubai) 至處理腳本:
<?php
// 接收參數
$src = $_POST['imgdata']; // 源文件路徑
$region = $_POST['region']; // 裁剪區域幾何描述 (JSON 或座標字符串)
$inout = (int)$_POST['inout']; // 內/外裁剪
$bg = (int)$_POST['toubai']; // 背景類型
$wand = NewMagickWand();
MagickReadImage($wand, $src);
// 根據形狀構建裁剪蒙版/路徑
// 矩形: MagickCropImage
// 圓形/圓角/弧形/多邊形: MagickCompositeImage + 遮罩圖層
// 任意形狀: 路徑剪裁
// 背景處理
if ($bg == 0) {
MagickSetImageBackgroundColor($wand, 'transparent');
} else {
MagickSetImageBackgroundColor($wand, 'white');
}
// 輸出
header('Content-Type: image/png'); // 或根據原格式
MagickWriteImage($wand, 'output.png');
?>
技術債與現代化重構建議
| 現狀 | 問題 | 重構方向 |
| 單文件 HTML/JS/CSS 混寫 | 不可維護、無法緩存、難協作 | 模塊化構建: Webpack/Vite + ES6 模塊 + SCSS + TypeScript |
| 原生 Canvas API 手寫幾何 | 邊界情況多、性能差、無撤銷/重做 | 引入 Fabric.js / Konva.js / Canvas 2D API 封裝庫 |
| iframe 上傳 + JS 回調 | 體驗差、錯誤處理難、跨域受限 | Fetch/XHR + FormData + Promise/async-await + 進度事件 |
| PHP 直接輸出 JS 腳本 | XSS 風險、前後端強耦合 | RESTful API 返回 JSON,前端路由渲染 |
| ImageMagick PHP 擴展 (imagick) | 版本鎖定、內存洩漏風險、併發弱 | 微服務化: 獨立圖片處理服務 + 消息隊列 + Object Storage |
| 演示版核心邏輯缺失 | 實際裁剪、保存、下載未實現 | 補全核心業務閉環 |
總結
這是一個典型的「豐富前端交互 + 服務端圖像處理」全棧案例。前端展示了 Canvas 繪圖、狀態機管理、複雜交互協調的硬核技巧;後端演示了 ImageMagick 在 PHP 中的基礎調用。雖代碼風格屬於 jQuery 時代產物,但其交互邏輯設計、幾何數據模型、前後端協議約定仍具備參考價值。現代化重構應遵循「前後端分離、組件化、服務化、雲原生」原則。
- 上一篇文章: PHP 自動分頁類實現原理與最佳實踐:從 SQL 改寫到 HTML 生成
- 下一篇文章: PHP 文件上傳類庫設計模式解析:配置驅動、鏈式調用與安全防護
Copyright ©
程式碼之家 All Rights Reserved