import { Command, FunctionCommand } from "./Command"; /** * 液化命令基类 * 所有液化相关命令的基类 */ export class LiquifyCommand extends Command { /** * 创建液化命令 * @param {Object} options 配置选项 * @param {Object} options.canvas Fabric.js画布实例 * @param {Object} options.layerManager 图层管理器实例 * @param {Object} options.liquifyManager 液化管理器实例 * @param {String} options.mode 液化模式 * @param {Object} options.params 液化参数 * @param {Object} options.targetObject 目标对象 * @param {ImageData} options.originalData 原始图像数据 * @param {ImageData} options.resultData 变形后图像数据 */ constructor(options) { super({ name: options.name || `液化操作: ${options.mode || "未知模式"}`, description: options.description || `使用${options.mode || "未知模式"}模式进行液化操作`, }); this.canvas = options.canvas; this.layerManager = options.layerManager; this.liquifyManager = options.liquifyManager; this.mode = options.mode; this.params = options.params || {}; this.targetObject = options.targetObject; this.targetLayerId = options.targetLayerId; this.originalData = options.originalData; // 操作前的图像数据 this.resultData = options.resultData; // 操作后的图像数据 this.savedState = null; } /** * 执行液化操作 * @returns {Promise} 执行结果 */ async execute() { if (!this.canvas || !this.targetObject) { throw new Error("液化命令缺少必要的画布或目标对象"); } if (!this.resultData) { // 如果没有预先计算的结果数据,现场执行变形 this.resultData = await this.liquifyManager.applyLiquify( this.targetObject, this.mode, this.params ); } // 保存执行前的状态 this.savedState = await this._saveObjectState(); // 更新画布上的对象 await this._updateObjectWithResult(); // 刷新Canvas this.canvas.renderAll(); return this.resultData; } /** * 撤销液化操作 * @returns {Promise} 撤销结果 */ async undo() { if (!this.canvas || !this.targetObject || !this.savedState) { throw new Error("无法撤销:缺少必要的状态信息"); } // 恢复对象到原始状态 await this._restoreObjectState(); // 刷新Canvas this.canvas.renderAll(); return true; } /** * 保存对象状态 * @private */ async _saveObjectState() { if (!this.targetObject) return null; // 对于图像对象,我们需要保存src和元数据 const state = { src: this.targetObject.getSrc ? this.targetObject.getSrc() : null, element: this.targetObject._element ? this.targetObject._element.cloneNode(true) : null, filters: this.targetObject.filters ? [...this.targetObject.filters] : [], originalData: this.originalData, targetLayerId: this.targetLayerId, }; return state; } /** * 恢复对象状态 * @private */ async _restoreObjectState() { if (!this.targetObject || !this.savedState) return false; // 获取当前图层对象 const layer = this.layerManager.getLayerById(this.savedState.targetLayerId); if (!layer) return false; // 恢复原始图像 if (this.savedState.element && this.targetObject.setElement) { this.targetObject.setElement(this.savedState.element); // 恢复滤镜 if (this.savedState.filters) { this.targetObject.filters = [...this.savedState.filters]; this.targetObject.applyFilters(); } } return true; } /** * 使用变形结果更新对象 * @private */ async _updateObjectWithResult() { if (!this.targetObject || !this.resultData) return false; // 创建临时canvas来渲染结果数据 const tempCanvas = document.createElement("canvas"); tempCanvas.width = this.resultData.width; tempCanvas.height = this.resultData.height; const tempCtx = tempCanvas.getContext("2d"); tempCtx.putImageData(this.resultData, 0, 0); console.log("临时Canvas创建成功 _updateObjectWithResult", this.resultData); // 更新Fabric图像 await new Promise((resolve) => { fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { // 保留原对象的属性 img.set({ left: this.targetObject.left, top: this.targetObject.top, scaleX: this.targetObject.scaleX, scaleY: this.targetObject.scaleY, angle: this.targetObject.angle, flipX: this.targetObject.flipX, flipY: this.targetObject.flipY, opacity: this.targetObject.opacity, }); // 替换Canvas上的对象 const index = this.canvas.getObjects().indexOf(this.targetObject); if (index !== -1) { this.canvas.remove(this.targetObject); this.canvas.insertAt(img, index); this.targetObject = img; } // 确保图层引用更新 const layer = this.layerManager.getLayerById(this.targetLayerId); if (layer) { if ( layer.type === "background" && layer.fabricObject === this.targetObject ) { layer.fabricObject = img; } else if (layer.fabricObjects) { const objIndex = layer.fabricObjects.indexOf(this.targetObject); if (objIndex !== -1) { layer.fabricObjects[objIndex] = img; } } } resolve(); }); }); return true; } } /** * 图层栅格化命令 * 用于将复杂图层栅格化为单一图像,以便进行液化操作 */ export class RasterizeForLiquifyCommand extends Command { /** * 创建栅格化命令 * @param {Object} options 配置选项 * @param {Object} options.canvas Fabric.js画布实例 * @param {Object} options.layerManager 图层管理器实例 * @param {String} options.layerId 需要栅格化的图层ID */ constructor(options) { super({ name: options.name || "栅格化图层", description: options.description || "将图层栅格化为单一图像以便液化操作", }); this.canvas = options.canvas; this.layerManager = options.layerManager; this.layerId = options.layerId; this.originalLayer = null; this.rasterizedImageObj = null; } /** * 执行栅格化操作 * @returns {Promise} 栅格化后的图像对象 */ async execute() { if (!this.canvas || !this.layerManager || !this.layerId) { throw new Error("栅格化命令缺少必要参数"); } // 保存原始图层信息 this.originalLayer = this.layerManager.getLayerById(this.layerId); if (!this.originalLayer) { throw new Error(`图层ID不存在: ${this.layerId}`); } // 栅格化图层 const rasterizedImage = await this.layerManager.rasterizeLayer( this.layerId ); if (!rasterizedImage) { throw new Error("栅格化图层失败"); } this.rasterizedImageObj = rasterizedImage; return rasterizedImage; } /** * 撤销栅格化操作 * 注意:完整撤销栅格化是复杂的,这里提供近似还原 * @returns {Promise} 撤销结果 */ async undo() { if (!this.canvas || !this.layerManager || !this.originalLayer) { throw new Error("无法撤销:缺少必要的状态信息"); } // 恢复图层为原始状态是复杂的,这里可能需要与LayerManager协作 // 这个实现可能需要根据实际的LayerManager功能来调整 const restored = await this.layerManager.restoreLayerFromBackup( this.layerId ); if (!restored) { console.warn("无法完全还原栅格化前的图层状态"); } return true; } } /** * 液化工具初始化命令 * 用于初始化液化工具的状态,不执行实际操作 */ export class InitLiquifyToolCommand extends Command { constructor(options) { super({ name: "初始化液化工具", description: "准备液化工具工作环境", undoable: false, // 这个命令不需要撤销 }); this.canvas = options.canvas; this.layerManager = options.layerManager; this.liquifyManager = options.liquifyManager; this.toolManager = options.toolManager; } /** * 执行初始化 */ execute() { if (this.liquifyManager) { this.liquifyManager.initialize({ canvas: this.canvas, layerManager: this.layerManager, }); } // 通知各管理器进入液化模式 this.toolManager?.notifyObservers("LIQUIFY"); return true; } undo() { // 不需要撤销初始化 return true; } } /** * 液化操作命令 - 针对单次变形操作 * 用于实现可撤销的单次液化变形 */ export class LiquifyDeformCommand extends LiquifyCommand { /** * 创建液化变形命令 * @param {Object} options 配置选项 * @param {Number} options.x 变形中心X坐标 * @param {Number} options.y 变形中心Y坐标 * @param {ImageData} options.beforeData 变形前的图像数据 * @param {ImageData} options.afterData 变形后的图像数据 */ constructor(options) { super({ ...options, name: `液化变形: ${options.mode || "未知模式"}`, description: `在(${options.x}, ${options.y})应用${ options.mode || "未知模式" }变形`, }); this.x = options.x; this.y = options.y; this.beforeData = options.beforeData; this.afterData = options.afterData; } async execute() { if (!this.afterData) { // 如果没有预计算的结果,实时计算 await this.liquifyManager.prepareForLiquify(this.targetObject); this.afterData = await this.liquifyManager.applyLiquify( this.targetObject, this.mode, this.params, this.x, this.y ); } // 保存当前状态 this.savedState = await this._saveObjectState(); // 应用变形结果 await this._updateObjectWithImageData(this.afterData); this.canvas.renderAll(); return this.afterData; } async undo() { if (!this.beforeData) { throw new Error("无法撤销:缺少变形前的数据"); } // 恢复到变形前的状态 await this._updateObjectWithImageData(this.beforeData); this.canvas.renderAll(); return true; } /** * 使用图像数据更新对象 * @param {ImageData} imageData 图像数据 * @private */ async _updateObjectWithImageData(imageData) { return new Promise((resolve) => { // 创建临时canvas const tempCanvas = document.createElement("canvas"); tempCanvas.width = imageData.width; tempCanvas.height = imageData.height; const tempCtx = tempCanvas.getContext("2d"); tempCtx.putImageData(imageData, 0, 0); // 从canvas创建新的fabric图像 fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { // 保留原对象的变换属性 img.set({ left: this.targetObject.left, top: this.targetObject.top, scaleX: this.targetObject.scaleX, scaleY: this.targetObject.scaleY, angle: this.targetObject.angle, flipX: this.targetObject.flipX, flipY: this.targetObject.flipY, opacity: this.targetObject.opacity, }); // 替换canvas上的对象 const index = this.canvas.getObjects().indexOf(this.targetObject); if (index !== -1) { this.canvas.remove(this.targetObject); this.canvas.insertAt(img, index); this.targetObject = img; // 更新图层引用 const layer = this.layerManager.getLayerById(this.targetLayerId); if (layer) { if ( layer.type === "background" && (layer.fabricObject === this.savedState?.originalObject || layer.fabricObject === this.targetObject) ) { layer.fabricObject = img; } else if (layer.fabricObjects) { const objIndex = layer.fabricObjects.findIndex( (obj) => obj === this.savedState?.originalObject || obj === this.targetObject ); if (objIndex !== -1) { layer.fabricObjects[objIndex] = img; } } } } resolve(); }); }); } } /** * 复合液化命令 - 用于组合多个液化操作 * 支持一次撤销多个相关的液化变形 */ export class CompositeLiquifyCommand extends Command { /** * 创建复合液化命令 * @param {Object} options 配置选项 * @param {Array} options.commands 子命令列表 * @param {String} options.name 命令名称 */ constructor(options) { super({ name: options.name || "液化操作组合", description: options.description || `包含${options.commands?.length || 0}个液化操作`, }); this.commands = options.commands || []; this.canvas = options.canvas; this.layerManager = options.layerManager; this.liquifyManager = options.liquifyManager; } /** * 添加子命令 * @param {Command} command 要添加的命令 */ addCommand(command) { this.commands.push(command); } async execute() { const results = []; for (const command of this.commands) { try { const result = await command.execute(); results.push(result); } catch (error) { // 如果有命令失败,尝试回滚已执行的命令 console.error("复合液化命令执行失败:", error); await this.undo(); throw error; } } return results; } async undo() { // 逆序撤销所有子命令 const errors = []; for (let i = this.commands.length - 1; i >= 0; i--) { try { await this.commands[i].undo(); } catch (error) { console.error(`撤销子命令${i}失败:`, error); errors.push(error); } } if (errors.length > 0) { throw new Error(`复合命令撤销部分失败: ${errors.length}个错误`); } return true; } /** * 检查命令是否可以执行 * @returns {Boolean} 是否可执行 */ canExecute() { return ( this.commands.length > 0 && this.commands.every((cmd) => (cmd.canExecute ? cmd.canExecute() : true)) ); } } /** * 液化重置命令 - 将图像恢复到原始状态 */ export class LiquifyResetCommand extends LiquifyCommand { constructor(options) { super({ ...options, name: "重置液化", description: "将图像恢复到液化前的原始状态", }); } async execute() { if (!this.liquifyManager || !this.targetObject) { throw new Error("无法重置:缺少必要的管理器或目标对象"); } // 保存当前状态 this.savedState = await this._saveObjectState(); // 重置液化管理器 const resetData = this.liquifyManager.reset(); if (!resetData) { throw new Error("重置失败:没有原始数据"); } // 应用重置结果 await this._updateObjectWithResult(); this.canvas.renderAll(); return resetData; } } /** * 辅助函数:创建液化重置命令 * @param {Object} options 配置选项 * @returns {LiquifyResetCommand} 重置命令实例 */ export function createLiquifyResetCommand(options) { return new LiquifyResetCommand(options); } /** * 辅助函数:创建液化变形命令 * @param {Object} options 配置选项 * @returns {LiquifyDeformCommand} 变形命令实例 */ export function createLiquifyDeformCommand(options) { return new LiquifyDeformCommand(options); } /** * 辅助函数:创建复合液化命令 * @param {Object} options 配置选项 * @returns {CompositeLiquifyCommand} 复合命令实例 */ export function createCompositeLiquifyCommand(options) { return new CompositeLiquifyCommand(options); }