首页 / 应用软件 / 开发指南,打造网站内嵌的在线简易图片编辑与美化工具

开发指南,打造网站内嵌的在线简易图片编辑与美化工具

开发指南:打造网站内嵌的在线简易图片编辑与美化工具

引言:为什么网站需要内置图片编辑工具?

在当今视觉内容主导的互联网环境中,图片已成为网站内容不可或缺的组成部分。无论是博客文章、产品展示还是社交媒体分享,高质量的图片都能显著提升用户体验和内容吸引力。然而,许多网站运营者面临一个共同挑战:用户上传的图片往往需要调整大小、裁剪、添加水印或进行简单美化,而传统的解决方案要么功能过于复杂,要么需要跳转到外部工具,导致用户体验中断。

WordPress作为全球最流行的内容管理系统,拥有强大的扩展能力。通过代码二次开发,我们可以在WordPress网站中嵌入一个轻量级的在线图片编辑与美化工具,让用户在不离开网站的情况下完成基本的图片处理操作。这不仅提升了用户体验,还能增加用户粘性和内容生产效率。

本文将详细介绍如何通过WordPress代码二次开发,实现一个功能完善但操作简单的内嵌图片编辑工具,涵盖从需求分析、技术选型到具体实现的完整流程。

一、需求分析与功能规划

1.1 核心功能需求

在开始开发之前,我们需要明确工具应具备的核心功能:

  1. 基础编辑功能

    • 图片裁剪与调整大小
    • 旋转与翻转
    • 亮度、对比度、饱和度调整
    • 锐化与模糊效果
  2. 美化增强功能

    • 滤镜与特效应用
    • 文字添加与样式设置
    • 贴图与形状叠加
    • 边框与阴影效果
  3. 实用工具

    • 图片压缩与格式转换
    • 水印添加与管理
    • 批量处理基础功能
    • 撤销/重做操作
  4. 用户体验需求

    • 响应式设计,适配不同设备
    • 直观的操作界面
    • 实时预览效果
    • 快速导出与保存

1.2 技术可行性分析

基于WordPress平台,我们有多种技术方案可选:

  1. 前端技术栈

    • HTML5 Canvas:用于图片处理的核心技术
    • JavaScript(ES6+):实现交互逻辑
    • CSS3:界面样式与动画效果
  2. 图片处理库选择

    • Fabric.js:功能强大的Canvas库,适合交互式图片编辑
    • Caman.js:专注于滤镜和颜色调整
    • 原生Canvas API:更轻量,但开发复杂度较高
  3. WordPress集成方案

    • 短代码(Shortcode)嵌入
    • Gutenberg块编辑器集成
    • 独立管理页面
    • 媒体库扩展

综合考虑开发效率与功能需求,我们选择Fabric.js作为核心图片处理库,通过短代码和媒体库扩展的方式集成到WordPress中。

二、开发环境搭建与准备工作

2.1 开发环境配置

  1. 本地WordPress环境

    • 安装Local by Flywheel或XAMPP
    • 配置PHP 7.4+环境
    • 确保启用GD库和ImageMagick扩展
  2. 代码编辑器准备

    • VS Code或PHPStorm
    • 安装WordPress开发相关插件
  3. 版本控制

    • 初始化Git仓库
    • 建立合理的分支管理策略

2.2 WordPress插件基础结构

创建插件目录结构:

wp-image-editor-tool/
├── wp-image-editor-tool.php      # 主插件文件
├── includes/                      # 核心功能文件
│   ├── class-editor-core.php     # 编辑器核心类
│   ├── class-image-processor.php # 图片处理类
│   └── class-ajax-handler.php    # AJAX处理类
├── admin/                         # 后台管理文件
│   ├── css/
│   ├── js/
│   └── class-admin-settings.php
├── public/                        # 前端文件
│   ├── css/
│   ├── js/
│   └── templates/
├── assets/                        # 静态资源
│   ├── fonts/
│   ├── icons/
│   └── images/
└── vendor/                        # 第三方库
    └── fabric.js/

2.3 插件主文件配置

<?php
/**
 * Plugin Name: WordPress图片编辑工具
 * Plugin URI: https://yourwebsite.com/
 * Description: 在WordPress网站中嵌入在线图片编辑与美化工具
 * Version: 1.0.0
 * Author: 你的名字
 * License: GPL v2 or later
 * Text Domain: wp-image-editor
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 定义插件常量
define('WPIET_VERSION', '1.0.0');
define('WPIET_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WPIET_PLUGIN_URL', plugin_dir_url(__FILE__));

// 初始化插件
require_once WPIET_PLUGIN_DIR . 'includes/class-plugin-init.php';

三、核心编辑器实现

3.1 Canvas编辑器初始化

创建编辑器核心类,初始化Fabric.js画布:

// public/js/editor-core.js
class ImageEditor {
    constructor(canvasId, options = {}) {
        this.canvas = new fabric.Canvas(canvasId, {
            backgroundColor: '#f5f5f5',
            preserveObjectStacking: true,
            ...options
        });
        
        this.history = [];
        this.historyIndex = -1;
        this.currentImage = null;
        this.initEvents();
    }
    
    initEvents() {
        // 保存操作历史
        this.canvas.on('object:modified', () => this.saveState());
        this.canvas.on('object:added', () => this.saveState());
        this.canvas.on('object:removed', () => this.saveState());
    }
    
    saveState() {
        // 限制历史记录数量
        if (this.history.length > 20) {
            this.history.shift();
        }
        
        this.history.push(JSON.stringify(this.canvas.toJSON()));
        this.historyIndex = this.history.length - 1;
    }
    
    loadImage(url) {
        return new Promise((resolve, reject) => {
            fabric.Image.fromURL(url, (img) => {
                this.canvas.clear();
                this.canvas.setBackgroundImage(img, this.canvas.renderAll.bind(this.canvas), {
                    scaleX: this.canvas.width / img.width,
                    scaleY: this.canvas.height / img.height
                });
                this.currentImage = img;
                this.saveState();
                resolve(img);
            }, {
                crossOrigin: 'anonymous'
            });
        });
    }
}

3.2 基础编辑功能实现

3.2.1 裁剪功能

class CropTool {
    constructor(editor) {
        this.editor = editor;
        this.isCropping = false;
        this.cropRect = null;
    }
    
    startCrop() {
        this.isCropping = true;
        this.cropRect = new fabric.Rect({
            left: 100,
            top: 100,
            width: 200,
            height: 200,
            fill: 'rgba(0,0,0,0.3)',
            stroke: '#ffffff',
            strokeWidth: 2,
            strokeDashArray: [5, 5],
            selectable: true,
            hasControls: true,
            hasBorders: true
        });
        
        this.editor.canvas.add(this.cropRect);
        this.editor.canvas.setActiveObject(this.cropRect);
    }
    
    applyCrop() {
        if (!this.cropRect || !this.editor.currentImage) return;
        
        const canvas = this.editor.canvas;
        const rect = this.cropRect;
        
        // 计算裁剪区域
        const scaleX = this.editor.currentImage.scaleX;
        const scaleY = this.editor.currentImage.scaleY;
        
        const cropData = {
            left: (rect.left - this.editor.currentImage.left) / scaleX,
            top: (rect.top - this.editor.currentImage.top) / scaleY,
            width: rect.width / scaleX,
            height: rect.height / scaleY
        };
        
        // 创建临时canvas进行裁剪
        const tempCanvas = document.createElement('canvas');
        const tempCtx = tempCanvas.getContext('2d');
        
        tempCanvas.width = cropData.width;
        tempCanvas.height = cropData.height;
        
        tempCtx.drawImage(
            canvas.lowerCanvasEl,
            cropData.left, cropData.top,
            cropData.width, cropData.height,
            0, 0,
            cropData.width, cropData.height
        );
        
        // 加载裁剪后的图片
        fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => {
            canvas.clear();
            canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
            this.editor.currentImage = img;
            this.editor.saveState();
            this.isCropping = false;
            this.cropRect = null;
        });
    }
}

3.2.2 调整工具

class AdjustmentTool {
    constructor(editor) {
        this.editor = editor;
    }
    
    adjustBrightness(value) {
        const filters = this.editor.currentImage.filters || [];
        const brightnessFilter = new fabric.Image.filters.Brightness({
            brightness: value / 100
        });
        
        // 查找并更新或添加亮度滤镜
        const existingIndex = filters.findIndex(f => f.type === 'Brightness');
        if (existingIndex >= 0) {
            filters[existingIndex] = brightnessFilter;
        } else {
            filters.push(brightnessFilter);
        }
        
        this.applyFilters(filters);
    }
    
    adjustContrast(value) {
        const filters = this.editor.currentImage.filters || [];
        const contrastFilter = new fabric.Image.filters.Contrast({
            contrast: value / 100
        });
        
        const existingIndex = filters.findIndex(f => f.type === 'Contrast');
        if (existingIndex >= 0) {
            filters[existingIndex] = contrastFilter;
        } else {
            filters.push(contrastFilter);
        }
        
        this.applyFilters(filters);
    }
    
    applyFilters(filters) {
        this.editor.currentImage.filters = filters;
        this.editor.currentImage.applyFilters();
        this.editor.canvas.renderAll();
        this.editor.saveState();
    }
}

3.3 美化功能实现

3.3.1 滤镜系统

class FilterSystem {
    constructor(editor) {
        this.editor = editor;
        this.presets = {
            vintage: {
                brightness: -0.05,
                saturation: 0.1,
                sepia: 0.3
            },
            blackWhite: {
                saturation: -1
            },
            cool: {
                brightness: 0.05,
                saturation: 0.2,
                tint: {
                    color: '#0099ff',
                    opacity: 0.1
                }
            },
            warm: {
                brightness: 0.05,
                saturation: 0.1,
                tint: {
                    color: '#ff9900',
                    opacity: 0.1
                }
            }
        };
    }
    
    applyPreset(presetName) {
        const preset = this.presets[presetName];
        if (!preset) return;
        
        const filters = [];
        
        if (preset.brightness !== undefined) {
            filters.push(new fabric.Image.filters.Brightness({
                brightness: preset.brightness
            }));
        }
        
        if (preset.saturation !== undefined) {
            filters.push(new fabric.Image.filters.Saturation({
                saturation: preset.saturation
            }));
        }
        
        if (preset.sepia !== undefined) {
            filters.push(new fabric.Image.filters.Sepia({
                amount: preset.sepia
            }));
        }
        
        if (preset.tint) {
            filters.push(new fabric.Image.filters.BlendColor({
                color: preset.tint.color,
                mode: 'tint',
                alpha: preset.tint.opacity
            }));
        }
        
        this.editor.currentImage.filters = filters;
        this.editor.currentImage.applyFilters();
        this.editor.canvas.renderAll();
        this.editor.saveState();
    }
    
    applyCustomFilter(filterConfig) {
        // 实现自定义滤镜组合
        const filters = [];
        
        Object.keys(filterConfig).forEach(key => {
            switch(key) {
                case 'brightness':
                    filters.push(new fabric.Image.filters.Brightness(filterConfig[key]));
                    break;
                case 'contrast':
                    filters.push(new fabric.Image.filters.Contrast(filterConfig[key]));
                    break;
                case 'saturation':
                    filters.push(new fabric.Image.filters.Saturation(filterConfig[key]));
                    break;
                // 更多滤镜类型...
            }
        });
        
        this.editor.currentImage.filters = filters;
        this.editor.currentImage.applyFilters();
        this.editor.canvas.renderAll();
        this.editor.saveState();
    }
}

3.3.2 文字添加功能

class TextTool {
    constructor(editor) {
        this.editor = editor;
        this.defaultStyles = {
            fontSize: 24,
            fontFamily: 'Arial',
            fill: '#000000',
            fontWeight: 'normal',
            textAlign: 'left'
        };
    }
    
    addText(content, options = {}) {
        const textOptions = {
            ...this.defaultStyles,
            ...options,
            left: this.editor.canvas.width / 2,
            top: this.editor.canvas.height / 2,
            editable: true
        };
        
        const text = new fabric.Textbox(content, textOptions);
        
        text.setControlsVisibility({
            mt: false, // 隐藏上中控制点
            mb: false  // 隐藏下中控制点
        });
        
        this.editor.canvas.add(text);
        this.editor.canvas.setActiveObject(text);
        this.editor.saveState();
        
        return text;
    }
    
    updateTextStyle(textObject, styles) {
        textObject.set(styles);
        this.editor.canvas.renderAll();
        this.editor.saveState();
    }
    
    addTextShadow(textObject, shadowConfig) {
        textObject.set({
            shadow: new fabric.Shadow({
                color: shadowConfig.color || 'rgba(0,0,0,0.5)',
                blur: shadowConfig.blur || 5,
                offsetX: shadowConfig.offsetX || 2,
                offsetY: shadowConfig.offsetY || 2
            })
        });
        
        this.editor.canvas.renderAll();
        this.editor.saveState();
    }
}

四、WordPress集成与后端处理

4.1 短代码集成

创建短代码,让用户可以在文章或页面中嵌入图片编辑器:

// includes/class-shortcode-handler.php
class WPIET_Shortcode_Handler {
    
    public static function init() {
        add_shortcode('wp_image_editor', [__CLASS__, 'render_editor']);
    }
    
    public static function render_editor($atts) {
        $atts = shortcode_atts([
            'width' => '800',
            'height' => '600',
            'image_id' => '',
            'toolbar' => 'basic'
        ], $atts);
        
        // 加载必要资源
        wp_enqueue_style('wpiet-editor-style');
        wp_enqueue_script('fabric-js');
        wp_enqueue_script('wpiet-editor-script');
        
        // 获取图片URL
        $image_url = '';
        if (!empty($atts['image_id'])) {
            $image_url = wp_get_attachment_url($atts['image_id']);
        }
        
        // 渲染编辑器HTML
        ob_start();
        ?>
        <div class="wpiet-editor-container" data-config="<?php echo esc_attr(json_encode($atts)); ?>">
            <div class="wpiet-toolbar">
                <!-- 工具栏内容 -->
            </div>
            <div class="wpiet-canvas-container">
                <canvas id="wpiet-canvas" 
                        width="<?php echo esc_attr($atts['width']); ?>" 
                        height="<?php echo esc_attr($atts['height']); ?>">
                </canvas>
            </div>
            <div class="wpiet-sidebar">
                <!-- 侧边栏工具 -->
            </div>
            <div class="wpiet-controls">
                <button class="wpiet-btn-save">保存图片</button>
                <button class="wpiet-btn-reset">重置</button>
            </div>
        </div>
        <?php
        return ob_get_clean();
    }
}

4.2 媒体库集成

扩展WordPress媒体库,添加"编辑图片"选项:

// includes/class-media-library-integration.php
class WPIET_Media_Library_Integration {
    
    public static function init() {
        // 在媒体库列表添加编辑链接
        add_filter('media_row_actions', [__CLASS__, 'add_edit_action'], 10, 2);
        
        // 在附件详情页添加编辑按钮
        add_action('attachment_submitbox_misc_actions', [__CLASS__, 'add_edit_button']);
        
        // 添加媒体库模态框中的编辑选项
        add_action('print_media_templates', [__CLASS__, 'add_media_template']);
    }
    
    public static function add_edit_action($actions, $post) {
        if (wp_attachment_is_image($post)) {
            $edit_url = admin_url('admin.php?page=wpiet-edit&image_id=' . $post->ID);
            $actions['wpiet_edit'] = sprintf(
                '<a href="%s" target="_blank">%s</a>',
                esc_url($edit_url),
                __('编辑图片', 'wp-image-editor')
            );
        }
        
        return $actions;
    }
    
    public static function add_edit_button() {
        global $post;
        
        if (!wp_attachment_is_image($post->ID)) {
            return;
        }
        
        ?>
        <div class="misc-pub-section">
            <a href="<?php echo admin_url('admin.php?page=wpiet-edit&image_id=' . $post->ID); ?>" 
               class="button button-large" 
               target="_blank">

开发指南:打造网站内嵌的在线简易图片编辑与美化工具(续)

4.3 AJAX图片处理与保存

4.3.1 后端图片处理类

// includes/class-image-processor.php
class WPIET_Image_Processor {
    
    private $allowed_mime_types = [
        'image/jpeg',
        'image/png',
        'image/gif',
        'image/webp'
    ];
    
    private $max_file_size = 5242880; // 5MB
    
    public function process_image($image_data, $operations = []) {
        // 验证图片数据
        if (!$this->validate_image_data($image_data)) {
            return new WP_Error('invalid_image', '无效的图片数据');
        }
        
        // 创建临时文件
        $temp_file = $this->create_temp_file($image_data);
        if (is_wp_error($temp_file)) {
            return $temp_file;
        }
        
        // 应用图片操作
        $processed_image = $this->apply_operations($temp_file, $operations);
        
        // 清理临时文件
        unlink($temp_file);
        
        return $processed_image;
    }
    
    private function validate_image_data($image_data) {
        // 检查数据格式
        if (!is_string($image_data) || empty($image_data)) {
            return false;
        }
        
        // 检查是否为有效的base64或URL
        if (strpos($image_data, 'data:image') === 0) {
            // base64格式
            $parts = explode(',', $image_data);
            if (count($parts) !== 2) {
                return false;
            }
            
            // 解码并验证
            $decoded = base64_decode($parts[1]);
            if ($decoded === false) {
                return false;
            }
            
            // 检查文件大小
            if (strlen($decoded) > $this->max_file_size) {
                return false;
            }
            
            // 检查MIME类型
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mime_type = finfo_buffer($finfo, $decoded);
            finfo_close($finfo);
            
            if (!in_array($mime_type, $this->allowed_mime_types)) {
                return false;
            }
        }
        
        return true;
    }
    
    private function create_temp_file($image_data) {
        $temp_dir = get_temp_dir();
        $temp_file = tempnam($temp_dir, 'wpiet_');
        
        if (strpos($image_data, 'data:image') === 0) {
            // base64数据
            $parts = explode(',', $image_data);
            $image_binary = base64_decode($parts[1]);
            file_put_contents($temp_file, $image_binary);
        } else {
            // URL或文件路径
            $response = wp_remote_get($image_data);
            if (is_wp_error($response)) {
                return $response;
            }
            
            $image_binary = wp_remote_retrieve_body($response);
            file_put_contents($temp_file, $image_binary);
        }
        
        return $temp_file;
    }
    
    private function apply_operations($image_path, $operations) {
        $editor = wp_get_image_editor($image_path);
        
        if (is_wp_error($editor)) {
            return $editor;
        }
        
        // 应用各项操作
        foreach ($operations as $operation) {
            switch ($operation['type']) {
                case 'crop':
                    $editor->crop(
                        $operation['x'],
                        $operation['y'],
                        $operation['width'],
                        $operation['height']
                    );
                    break;
                    
                case 'resize':
                    $editor->resize(
                        $operation['width'],
                        $operation['height'],
                        $operation['crop'] ?? false
                    );
                    break;
                    
                case 'rotate':
                    $editor->rotate($operation['angle']);
                    break;
                    
                case 'flip':
                    $editor->flip(
                        $operation['direction'] === 'horizontal' ? 'horiz' : 'vert'
                    );
                    break;
                    
                case 'filter':
                    $this->apply_filter($editor, $operation);
                    break;
            }
        }
        
        // 生成新文件名
        $filename = 'edited-' . time() . '-' . wp_basename($image_path);
        $upload_dir = wp_upload_dir();
        $file_path = $upload_dir['path'] . '/' . $filename;
        
        // 保存图片
        $result = $editor->save($file_path);
        
        if (is_wp_error($result)) {
            return $result;
        }
        
        return [
            'path' => $result['path'],
            'url' => $upload_dir['url'] . '/' . $result['file'],
            'width' => $result['width'],
            'height' => $result['height'],
            'size' => filesize($result['path'])
        ];
    }
    
    private function apply_filter($editor, $filter) {
        // 使用ImageMagick或GD应用滤镜
        $image_path = $editor->get_file();
        
        if (extension_loaded('imagick')) {
            $this->apply_imagick_filter($image_path, $filter);
        } else {
            $this->apply_gd_filter($image_path, $filter);
        }
    }
    
    private function apply_imagick_filter($image_path, $filter) {
        $imagick = new Imagick($image_path);
        
        switch ($filter['name']) {
            case 'brightness':
                $imagick->modulateImage(
                    $filter['value'] + 100,
                    100,
                    100
                );
                break;
                
            case 'contrast':
                $imagick->sigmoidalContrastImage(
                    true,
                    $filter['value'] / 10,
                    0
                );
                break;
                
            case 'saturation':
                $imagick->modulateImage(
                    100,
                    $filter['value'] + 100,
                    100
                );
                break;
                
            case 'sepia':
                $imagick->sepiaToneImage($filter['value']);
                break;
                
            case 'blur':
                $imagick->gaussianBlurImage(
                    $filter['radius'],
                    $filter['sigma']
                );
                break;
        }
        
        $imagick->writeImage($image_path);
        $imagick->destroy();
    }
}

4.3.2 AJAX处理器

// includes/class-ajax-handler.php
class WPIET_Ajax_Handler {
    
    public static function init() {
        // 保存图片
        add_action('wp_ajax_wpiet_save_image', [__CLASS__, 'save_image']);
        add_action('wp_ajax_nopriv_wpiet_save_image', [__CLASS__, 'save_image_nopriv']);
        
        // 获取图片信息
        add_action('wp_ajax_wpiet_get_image_info', [__CLASS__, 'get_image_info']);
        
        // 批量处理
        add_action('wp_ajax_wpiet_batch_process', [__CLASS__, 'batch_process']);
    }
    
    public static function save_image() {
        // 验证nonce
        if (!check_ajax_referer('wpiet_editor_nonce', 'nonce', false)) {
            wp_die('安全验证失败', 403);
        }
        
        // 验证权限
        if (!current_user_can('upload_files')) {
            wp_die('权限不足', 403);
        }
        
        // 获取数据
        $image_data = isset($_POST['image_data']) ? $_POST['image_data'] : '';
        $operations = isset($_POST['operations']) ? json_decode(stripslashes($_POST['operations']), true) : [];
        $filename = isset($_POST['filename']) ? sanitize_file_name($_POST['filename']) : '';
        
        if (empty($image_data)) {
            wp_send_json_error('没有图片数据');
        }
        
        // 处理图片
        $processor = new WPIET_Image_Processor();
        $result = $processor->process_image($image_data, $operations);
        
        if (is_wp_error($result)) {
            wp_send_json_error($result->get_error_message());
        }
        
        // 创建媒体库附件
        $attachment_id = self::create_attachment($result['path'], $filename);
        
        if (is_wp_error($attachment_id)) {
            wp_send_json_error($attachment_id->get_error_message());
        }
        
        // 返回结果
        wp_send_json_success([
            'attachment_id' => $attachment_id,
            'url' => $result['url'],
            'edit_url' => get_edit_post_link($attachment_id),
            'size' => size_format($result['size'])
        ]);
    }
    
    public static function save_image_nopriv() {
        // 非登录用户处理
        if (!get_option('wpiet_allow_guest_upload', false)) {
            wp_die('请登录后操作', 403);
        }
        
        // 验证reCAPTCHA(如果启用)
        if (get_option('wpiet_enable_recaptcha', false)) {
            $recaptcha_response = isset($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : '';
            
            if (!self::verify_recaptcha($recaptcha_response)) {
                wp_send_json_error('验证码验证失败');
            }
        }
        
        // 继续处理图片
        self::save_image();
    }
    
    private static function create_attachment($file_path, $filename) {
        $file_type = wp_check_filetype($filename, null);
        
        $attachment = [
            'post_mime_type' => $file_type['type'],
            'post_title' => preg_replace('/.[^.]+$/', '', $filename),
            'post_content' => '',
            'post_status' => 'inherit',
            'guid' => wp_get_upload_dir()['url'] . '/' . $filename
        ];
        
        $attachment_id = wp_insert_attachment($attachment, $file_path);
        
        if (is_wp_error($attachment_id)) {
            return $attachment_id;
        }
        
        // 生成附件元数据
        require_once(ABSPATH . 'wp-admin/includes/image.php');
        $attachment_data = wp_generate_attachment_metadata($attachment_id, $file_path);
        wp_update_attachment_metadata($attachment_id, $attachment_data);
        
        return $attachment_id;
    }
    
    private static function verify_recaptcha($response) {
        $secret_key = get_option('wpiet_recaptcha_secret_key', '');
        
        if (empty($secret_key)) {
            return true;
        }
        
        $verify_url = 'https://www.google.com/recaptcha/api/siteverify';
        $verify_data = [
            'secret' => $secret_key,
            'response' => $response,
            'remoteip' => $_SERVER['REMOTE_ADDR']
        ];
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $verify_url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($verify_data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        
        $result = curl_exec($ch);
        curl_close($ch);
        
        $result_data = json_decode($result, true);
        
        return isset($result_data['success']) && $result_data['success'] === true;
    }
}

五、前端界面与用户体验优化

5.1 响应式编辑器界面

// public/js/editor-ui.js
class EditorUI {
    constructor(editorInstance) {
        this.editor = editorInstance;
        this.uiState = {
            activeTool: null,
            isMobile: window.innerWidth < 768,
            isFullscreen: false,
            showSidebar: true
        };
        
        this.initUI();
        this.bindEvents();
        this.adaptLayout();
    }
    
    initUI() {
        // 创建工具栏
        this.createToolbar();
        
        // 创建侧边栏
        this.createSidebar();
        
        // 创建底部控制栏
        this.createControls();
        
        // 创建模态框
        this.createModals();
    }
    
    createToolbar() {
        const toolbarHTML = `
            <div class="wpiet-toolbar">
                <div class="toolbar-section file">
                    <button class="toolbar-btn" data-action="open">
                        <i class="icon-folder-open"></i>
                        <span>打开</span>
                    </button>
                    <button class="toolbar-btn" data-action="save">
                        <i class="icon-save"></i>
                        <span>保存</span>
                    </button>
                    <button class="toolbar-btn" data-action="export">
                        <i class="icon-download"></i>
                        <span>导出</span>
                    </button>
                </div>
                
                <div class="toolbar-section edit">
                    <button class="toolbar-btn" data-tool="crop">
                        <i class="icon-crop"></i>
                        <span>裁剪</span>
                    </button>
                    <button class="toolbar-btn" data-tool="rotate">
                        <i class="icon-rotate-right"></i>
                        <span>旋转</span>
                    </button>
                    <button class="toolbar-btn" data-tool="flip">
                        <i class="icon-flip-horizontal"></i>
                        <span>翻转</span>
                    </button>
                    <button class="toolbar-btn" data-tool="adjust">
                        <i class="icon-sliders"></i>
                        <span>调整</span>
                    </button>
                </div>
                
                <div class="toolbar-section effects">
                    <button class="toolbar-btn" data-tool="filter">
                        <i class="icon-filter"></i>
                        <span>滤镜</span>
                    </button>
                    <button class="toolbar-btn" data-tool="text">
                        <i class="icon-type"></i>
                        <span>文字</span>
                    </button>
                    <button class="toolbar-btn" data-tool="sticker">
                        <i class="icon-sticker"></i>
                        <span>贴图</span>
                    </button>
                    <button class="toolbar-btn" data-tool="frame">
                        <i class="icon-square"></i>
                        <span>边框</span>
                    </button>
                </div>
                
                <div class="toolbar-section view">
                    <button class="toolbar-btn" data-action="zoom-in">
                        <i class="icon-zoom-in"></i>
                    </button>
                    <button class="toolbar-btn" data-action="zoom-out">
                        <i class="icon-zoom-out"></i>
                    </button>
                    <button class="toolbar-btn" data-action="fullscreen">
                        <i class="icon-maximize"></i>
                    </button>
                    <button class="toolbar-btn" data-action="toggle-sidebar">
                        <i class="icon-sidebar"></i>
                    </button>
                </div>
            </div>
        `;
        
        document.querySelector('.wpiet-editor-container').insertAdjacentHTML('afterbegin', toolbarHTML);
    }
    
    createSidebar() {
        const sidebarHTML = `
            <div class="wpiet-sidebar ${this.uiState.showSidebar ? 'active' : ''}">
                <div class="sidebar-header">
                    <h3>工具选项</h3>
                    <button class="sidebar-close">&times;</button>
                </div>
                
                <div class="sidebar-content">
                    <!-- 动态内容 -->
                    <div class="tool-options" id="tool-options">
                        <div class="empty-state">
                            <i class="icon-tool"></i>
                            <p>选择一个工具开始编辑</p>
                        </div>
                    </div>
                    
                    <!-- 历史记录 -->
                    <div class="history-section">
                        <h4>历史记录</h4>
                        <div class="history-list" id="history-list"></div>
                        <div class="history-controls">
                            <button class="btn-small" id="undo-btn" disabled>
                                <i class="icon-undo"></i> 撤销
                            </button>
                            <button class="btn-small" id="redo-btn" disabled>
                                <i class="icon-redo"></i> 重做
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        `;
        
        document.querySelector('.wpiet-editor-container').insertAdjacentHTML('beforeend', sidebarHTML);
    }
    
    bindEvents() {
        // 工具栏按钮点击
        document.querySelectorAll('.toolbar-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const action = e.currentTarget.dataset.action;
                const tool = e.currentTarget.dataset.tool;
                
                if (action) {
                    this.handleAction(action);
                } else if (tool) {
                    this.activateTool(tool);
                }
            });
        });
        
        // 窗口大小变化
        window.addEventListener('resize', () => {
            this.adaptLayout();
        });
        
        // 键盘快捷键
        document.addEventListener('keydown', (e) => {
            this.handleKeyboardShortcuts(e);
        });
        
        // 触摸设备支持
        if ('ontouchstart' in window) {
            this.enableTouchSupport();
        }
    }
    
    handleAction(action) {
        switch(action) {
            case 'open':
                this.openImagePicker();
                break;
                
            case 'save':
                this.saveImage();
                break;
                
            case 'export':
                this.exportImage();
                break;
                
            case 'zoom-in':
                this.editor.zoomIn();
                break;
                
            case 'zoom-out':
                this.editor.zoomOut();
                break;
                
            case 'fullscreen':
                this.toggleFullscreen();
                break;
                
            case 'toggle-sidebar':
                this.toggleSidebar();
                break;
        }
    }
    
    activateTool(toolName) {
        // 更新UI状态
        this.uiState.activeTool = toolName;
        
        // 更新工具栏按钮状态
        document.querySelectorAll('.toolbar-btn').forEach(btn => {
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5248.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部