Files
aida_front/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js

1229 lines
36 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Command, FunctionCommand } from "./Command";
import { getLiquifyReferenceManager } from "../managers/LiquifyReferenceManager";
import { optimizeCanvasRendering } from "../utils/helper";
import { fabric } from "fabric-with-all";
/**
* 液化命令基类
* 所有液化相关命令的基类
*/
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();
// 注意_updateObjectWithResult 内部已使用 optimizeCanvasRendering会自动渲染
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;
}
/**
* 使用变形结果更新对象
* 优化:直接使用 setElement 更新现有对象,避免创建新对象和替换操作
* @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);
// 使用优化渲染工具,避免图层闪烁
await optimizeCanvasRendering(this.canvas, async () => {
// 预加载图像元素,确保完全加载后再更新
await this._updateObjectElementDirectly(tempCanvas.toDataURL());
});
return true;
}
/**
* 直接更新对象的图像元素,避免对象替换造成的图层闪烁
* @param {String} imageDataURL 图像数据的 DataURL
* @private
*/
async _updateObjectElementDirectly(imageDataURL) {
return new Promise((resolve, reject) => {
// 创建 HTMLImageElement 并预加载
const imgElement = new Image();
imgElement.onload = () => {
try {
// 保存当前对象状态(非图像属性)
const currentState = {
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,
};
// 直接更新现有对象的图像元素,保持对象引用不变
if (this.targetObject.setElement) {
this.targetObject.setElement(imgElement);
} else if (this.targetObject._element) {
this.targetObject._element = imgElement;
this.targetObject._originalElement = imgElement;
}
// 恢复对象属性setElement 可能会重置一些属性)
this.targetObject.set(currentState);
// 标记对象需要重新渲染
this.targetObject.dirty = true;
this.targetObject.setCoords();
resolve();
} catch (error) {
console.error("更新对象元素失败:", error);
reject(error);
}
};
imgElement.onerror = () => {
reject(new Error("图像加载失败"));
};
// 开始加载图像
imgElement.src = imageDataURL;
});
}
/**
* 安全地替换对象,避免图层闪烁(保留作为备用方法)
* @param {Object} newImg 新的fabric图像对象
* @private
*/
_replaceObjectSafely(newImg) {
// 保存旧对象引用,用于更新图层引用
const oldObject = this.targetObject;
// 替换Canvas上的对象
const index = this.canvas.getObjects().indexOf(oldObject);
if (index !== -1) {
// 在禁用自动渲染的情况下,先插入新对象,再移除旧对象
// 这样可以避免中间出现空白因为renderOnAddRemove已被禁用
this.canvas.insertAt(newImg, index);
this.canvas.remove(oldObject);
this.targetObject = newImg;
}
// 确保图层引用更新
const layer = this.layerManager.getLayerById(this.targetLayerId);
if (layer) {
if (layer.type === "background" && layer.fabricObject === oldObject) {
layer.fabricObject = newImg;
} else if (layer.fabricObjects) {
const objIndex = layer.fabricObjects.indexOf(oldObject);
if (objIndex !== -1) {
layer.fabricObjects[objIndex] = newImg;
}
}
}
}
}
/**
* 液化工具初始化命令
* 用于初始化液化工具的状态,不执行实际操作
*/
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);
// 注意_updateObjectWithImageData 内部已使用 optimizeCanvasRendering会自动渲染
return this.afterData;
}
async undo() {
if (!this.beforeData) {
throw new Error("无法撤销:缺少变形前的数据");
}
// 恢复到变形前的状态
await this._updateObjectWithImageData(this.beforeData);
// 注意_updateObjectWithImageData 内部已使用 optimizeCanvasRendering会自动渲染
return true;
}
/**
* 使用图像数据更新对象
* 优化:直接使用 setElement 更新现有对象,避免创建新对象和替换操作
* @param {ImageData} imageData 图像数据
* @private
*/
async _updateObjectWithImageData(imageData) {
// 创建临时canvas
const tempCanvas = document.createElement("canvas");
tempCanvas.width = imageData.width;
tempCanvas.height = imageData.height;
const tempCtx = tempCanvas.getContext("2d");
tempCtx.putImageData(imageData, 0, 0);
// 使用优化渲染工具,避免图层闪烁
await optimizeCanvasRendering(this.canvas, async () => {
// 直接更新对象元素,避免对象替换
await this._updateObjectElementDirectly(tempCanvas.toDataURL());
});
}
/**
* 安全地替换变形对象,避免图层闪烁(保留作为备用方法)
* @param {Object} newImg 新的fabric图像对象
* @private
*/
_replaceDeformObjectSafely(newImg) {
// 保存旧对象引用,用于更新图层引用
const oldObject = this.targetObject;
// 替换Canvas上的对象
const index = this.canvas.getObjects().indexOf(oldObject);
if (index !== -1) {
// 在禁用自动渲染的情况下,先插入新对象,再移除旧对象
// 这样可以避免中间出现空白
this.canvas.insertAt(newImg, index);
this.canvas.remove(oldObject);
this.targetObject = newImg;
}
// 更新图层引用
const layer = this.layerManager.getLayerById(this.targetLayerId);
if (layer) {
if (
layer.type === "background" &&
(layer.fabricObject === this.savedState?.originalObject ||
layer.fabricObject === oldObject)
) {
layer.fabricObject = newImg;
} else if (layer.fabricObjects) {
const objIndex = layer.fabricObjects.findIndex(
(obj) => obj === this.savedState?.originalObject || obj === oldObject
);
if (objIndex !== -1) {
layer.fabricObjects[objIndex] = newImg;
}
}
}
}
}
/**
* 复合液化命令 - 用于组合多个液化操作
* 支持一次撤销多个相关的液化变形
*/
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;
}
}
/**
* 液化状态命令 - 最优化版本
* 使用引用管理器避免对象引用丢失,支持高性能的状态管理
*/
export class LiquifyStateCommand extends Command {
/**
* 创建液化状态命令
* @param {Object} options 配置选项
* @param {Object} options.canvas Fabric.js画布实例
* @param {Object} options.layerManager 图层管理器实例
* @param {Object} options.targetObject 目标对象(保持引用)
* @param {String} options.targetLayerId 目标图层ID
* @param {ImageData} options.initialImageData 初始图像数据
* @param {ImageData} options.finalImageData 最终图像数据
* @param {Object} options.liquifyManager 液化管理器实例
*/
constructor(options) {
super({
name: options.name || "液化操作",
description: options.description || "液化变形操作的状态记录",
});
this.canvas = options.canvas;
this.layerManager = options.layerManager;
this.targetObject = options.targetObject;
this.targetLayerId = options.targetLayerId;
this.targetObjectId = options.targetObjectId;
this.liquifyManager = options.liquifyManager; // 添加液化管理器引用
// 获取引用管理器实例
this.refManager = getLiquifyReferenceManager();
// 实时更新实例
this.realtimeUpdater = options.realtimeUpdater || null;
// 注册对象到引用管理器
this.objectRefId = this.refManager.registerObject(
this.targetObject,
this.targetObjectId || `liquify_${Date.now()}`
);
// 保存状态快照ID
this.initialSnapshotId = null;
this.finalSnapshotId = null;
// 设置图像数据
this.initialImageData = options.initialImageData;
this.finalImageData = options.finalImageData;
// 保存液化管理器的操作记录状态
this.initialLiquifyState = null;
this.finalLiquifyState = null;
this.currentState = "initial";
// 创建初始快照
if (this.initialImageData) {
this._createInitialSnapshot();
}
}
/**
* 执行命令 - 应用最终状态
*/
async execute() {
if (!this.finalImageData) {
throw new Error("缺少最终状态数据");
}
// 确保有最终状态快照
if (!this.finalSnapshotId) {
await this._createFinalSnapshot();
}
// 通过引用管理器更新图像数据
await this.refManager.updateObjectImageData(this.objectRefId, this.finalImageData);
// 恢复液化管理器到最终状态
if (this.liquifyManager && this.finalLiquifyState) {
this._restoreLiquifyManagerState(this.finalLiquifyState);
} else if (this.liquifyManager) {
// 如果没有保存的最终状态,重新准备液化环境
const currentTarget = this.refManager.getObjectRef(this.objectRefId);
if (currentTarget) {
await this.liquifyManager.prepareForLiquify(currentTarget);
// 保存当前的液化管理器状态作为最终状态
this.finalLiquifyState = this._captureLiquifyManagerState();
}
}
this.currentState = "final";
this.canvas.renderAll();
console.log("✅ 液化命令执行完成,应用最终状态");
return true;
}
/**
* 撤销命令 - 恢复初始状态
*/
async undo() {
if (!this.initialImageData || !this.initialSnapshotId) {
throw new Error("缺少初始状态数据或快照");
}
// 通过引用管理器恢复到初始快照
await this.refManager.restoreFromSnapshot(this.objectRefId, this.initialSnapshotId);
// 恢复液化管理器到初始状态 - 关键修复
if (this.liquifyManager) {
// if (this.initialLiquifyState) {
// this._restoreLiquifyManagerState(this.initialLiquifyState);
// } else {
// 如果没有初始状态,重置液化管理器并重新初始化
this.liquifyManager.reset();
const currentTarget = this.refManager.getObjectRef(this.objectRefId);
if (currentTarget) {
// 重新准备液化环境,使用初始图像数据
await this.liquifyManager.prepareForLiquify(currentTarget);
// 强制设置原始图像数据为初始状态
if (this.liquifyManager.enhancedManager) {
this.liquifyManager.enhancedManager.originalImageData = this.initialImageData;
this.liquifyManager.enhancedManager.currentImageData = this._cloneImageData(
this.initialImageData
);
// 重置激活渲染器的数据
if (this.liquifyManager.enhancedManager.activeRenderer) {
const renderer = this.liquifyManager.enhancedManager.activeRenderer;
renderer.originalImageData = this.initialImageData;
renderer.currentImageData = this._cloneImageData(this.initialImageData);
// 重置CPU渲染器的网格和变形历史
if (renderer.reset) {
renderer.reset();
}
// }
}
}
}
// 确保实时更新器使用正确的目标对象和初始数据
if (this.realtimeUpdater) {
const currentTarget = this.refManager.getObjectRef(this.objectRefId);
this.realtimeUpdater.targetObject = currentTarget;
// 重置实时更新器的内部状态
if (this.realtimeUpdater.reset) {
this.realtimeUpdater.reset();
}
}
}
this.currentState = "initial";
this.canvas.renderAll();
console.log("🔄 液化命令撤销完成,恢复初始状态(已重置所有内部状态)");
return true;
}
/**
* 重做命令 - 重新应用最终状态
*/
async redo() {
return this.execute();
}
/**
* 设置最终状态的图像数据
* @param {ImageData} finalImageData 最终状态的图像数据
*/
setFinalImageData(finalImageData) {
this.finalImageData = finalImageData;
this.finalSnapshotId = null; // 重置快照ID下次执行时重新创建
// 捕获当前液化管理器状态作为最终状态
if (this.liquifyManager) {
this.finalLiquifyState = this._captureLiquifyManagerState();
}
}
/**
* 获取当前状态标记
* @returns {String} 'initial' 或 'final'
*/
getCurrentState() {
return this.currentState;
}
/**
* 检查命令是否有效
* @returns {Boolean} 是否有效
*/
isValid() {
const targetObject = this.refManager.getObjectRef(this.objectRefId);
return !!(targetObject && this.initialImageData && this.finalImageData);
}
/**
* 获取目标对象的当前引用
* @returns {Object|null} Fabric对象
*/
getTargetObject() {
return this.refManager.getObjectRef(this.objectRefId);
}
/**
* 清理资源
*/
dispose() {
if (this.objectRefId) {
// 清理快照
if (this.initialSnapshotId) {
this.refManager.stateSnapshots.delete(this.initialSnapshotId);
}
if (this.finalSnapshotId) {
this.refManager.stateSnapshots.delete(this.finalSnapshotId);
}
// 注意:不要清理对象引用,因为可能有其他命令在使用
console.log(`🗑️ 液化状态命令资源已清理: ${this.objectRefId}`);
}
}
/**
* 获取内存使用统计
* @returns {Object} 统计信息
*/
getMemoryStats() {
const refManagerStats = this.refManager.getMemoryStats();
const commandMemory = this._calculateCommandMemory();
return {
...refManagerStats,
commandMemory,
totalCommandMemory: commandMemory,
};
}
// 私有方法
/**
* 创建初始状态快照
* @private
*/
async _createInitialSnapshot() {
if (!this.initialImageData) return;
this.initialSnapshotId = `${this.objectRefId}_initial_${Date.now()}`;
// 手动创建初始快照,包含图像数据
const fabricObject = this.refManager.getObjectRef(this.objectRefId);
if (fabricObject) {
const snapshot = {
timestamp: Date.now(),
properties: this.refManager._captureObjectState(fabricObject),
imageData: this.initialImageData,
eventListeners: this.refManager.eventListeners.get(this.objectRefId) || {},
};
this.refManager.stateSnapshots.set(this.initialSnapshotId, snapshot);
// 捕获初始液化管理器状态
if (this.liquifyManager) {
this.initialLiquifyState = this._captureLiquifyManagerState();
}
console.log(`📸 初始状态快照已创建: ${this.initialSnapshotId}`);
}
}
/**
* 创建最终状态快照
* @private
*/
async _createFinalSnapshot() {
if (!this.finalImageData) return;
this.finalSnapshotId = `${this.objectRefId}_final_${Date.now()}`;
// 手动创建最终快照,包含图像数据
const fabricObject = this.refManager.getObjectRef(this.objectRefId);
if (fabricObject) {
const snapshot = {
timestamp: Date.now(),
properties: this.refManager._captureObjectState(fabricObject),
imageData: this.finalImageData,
eventListeners: this.refManager.eventListeners.get(this.objectRefId) || {},
};
this.refManager.stateSnapshots.set(this.finalSnapshotId, snapshot);
// 捕获最终液化管理器状态
if (this.liquifyManager) {
this.finalLiquifyState = this._captureLiquifyManagerState();
}
console.log(`📸 最终状态快照已创建: ${this.finalSnapshotId}`);
}
}
/**
* 捕获液化管理器的当前状态
* @returns {Object} 液化管理器状态
* @private
*/
_captureLiquifyManagerState() {
if (!this.liquifyManager) return null;
try {
const enhancedManager = this.liquifyManager.enhancedManager;
const state = {
// 捕获增强管理器状态
enhancedManagerState: null,
// 捕获当前渲染器状态
activeRendererState: null,
// 捕获目标对象引用
targetObjectRef: this.liquifyManager.targetObject ?? enhancedManager.targetObject,
// 捕获初始化状态
initialized: this.liquifyManager.initialized || false,
};
// 如果有增强管理器,捕获其状态
if (this.liquifyManager.enhancedManager) {
state.enhancedManagerState = {
initialized: enhancedManager.initialized,
renderMode: enhancedManager.renderMode,
targetObject: enhancedManager.targetObject,
originalImageData: enhancedManager.originalImageData,
currentImageData: enhancedManager.currentImageData,
params: { ...enhancedManager.params },
currentMode: enhancedManager.currentMode,
};
// 如果有激活的渲染器,捕获其状态
if (enhancedManager.activeRenderer) {
const renderer = enhancedManager.activeRenderer;
state.activeRendererState = {
initialized: renderer.initialized,
originalImageData: renderer.originalImageData,
currentImageData: renderer.currentImageData,
params: { ...renderer.params },
currentMode: renderer.currentMode,
// 对于CPU渲染器还需要保存网格状态
meshState: renderer.mesh ? this._captureMeshState(renderer.mesh) : null,
// 保存变形历史
deformHistory: renderer.deformHistory ? [...renderer.deformHistory] : [],
};
}
}
console.log(`💾 液化管理器状态已捕获:`, state);
return state;
} catch (error) {
console.error("捕获液化管理器状态失败:", error);
return null;
}
}
/**
* 恢复液化管理器状态
* @param {Object} state 要恢复的状态
* @private
*/
_restoreLiquifyManagerState(state) {
if (!this.liquifyManager || !state) return;
try {
// 恢复基本状态
this.liquifyManager.initialized = state.initialized;
if (state.targetObjectRef) {
this.liquifyManager.targetObject = state.targetObjectRef;
}
// 确保实时更新器使用正确的目标对象
if (this.realtimeUpdater) {
this.realtimeUpdater.targetObject = this.liquifyManager.targetObject;
// 如果有setTargetObject方法调用它
if (typeof this.realtimeUpdater.setTargetObject === "function") {
this.realtimeUpdater.setTargetObject(this.liquifyManager.targetObject);
}
}
// 恢复增强管理器状态
if (state.enhancedManagerState && this.liquifyManager.enhancedManager) {
const enhancedManager = this.liquifyManager.enhancedManager;
const enhancedState = state.enhancedManagerState;
enhancedManager.initialized = enhancedState.initialized;
enhancedManager.renderMode = enhancedState.renderMode;
enhancedManager.targetObject = enhancedState.targetObject;
// 关键修复:确保图像数据被正确恢复
enhancedManager.originalImageData = enhancedState.originalImageData;
enhancedManager.currentImageData = enhancedState.currentImageData;
enhancedManager.params = { ...enhancedState.params };
enhancedManager.currentMode = enhancedState.currentMode;
// 恢复激活渲染器状态
if (state.activeRendererState && enhancedManager.activeRenderer) {
const renderer = enhancedManager.activeRenderer;
const rendererState = state.activeRendererState;
renderer.initialized = rendererState.initialized;
// 关键修复:强制重置渲染器的图像数据
renderer.originalImageData = rendererState.originalImageData;
renderer.currentImageData = rendererState.currentImageData;
renderer.params = { ...rendererState.params };
renderer.currentMode = rendererState.currentMode;
// 恢复网格状态如果是CPU渲染器
if (rendererState.meshState && renderer.mesh) {
this._restoreMeshState(renderer.mesh, rendererState.meshState);
} else if (renderer.mesh && renderer._initMesh) {
// 如果没有保存的网格状态,重新初始化网格
renderer._initMesh(
rendererState.originalImageData?.width || renderer.originalImageData?.width,
rendererState.originalImageData?.height || renderer.originalImageData?.height
);
}
// 重置变形历史
if (rendererState.deformHistory) {
renderer.deformHistory = [...rendererState.deformHistory];
} else {
// 如果没有保存的历史,清空变形历史
renderer.deformHistory = [];
}
// 重置持续按压相关状态(如果存在)
if (renderer.isHolding !== undefined) {
renderer.isHolding = false;
renderer.pressStartTime = 0;
renderer.pressDuration = 0;
renderer.accumulatedRotation = 0;
renderer.accumulatedScale = 0;
renderer.lastApplyTime = 0;
}
// 重置拖拽状态(如果存在)
if (renderer.isDragging !== undefined) {
renderer.isDragging = false;
renderer.dragDistance = 0;
renderer.dragAngle = 0;
renderer.isFirstApply = true;
}
}
}
console.log(`🔄 液化管理器状态已恢复(包含完整的数据重置)`);
} catch (error) {
console.error("恢复液化管理器状态失败:", error);
}
}
/**
* 捕获网格状态
* @param {Array} mesh 网格数组
* @returns {Array} 网格状态副本
* @private
*/
_captureMeshState(mesh) {
if (!mesh || !Array.isArray(mesh)) return null;
return mesh.map((row) =>
row.map((point) => ({
x: point.x,
y: point.y,
originalX: point.originalX,
originalY: point.originalY,
}))
);
}
/**
* 恢复网格状态
* @param {Array} mesh 目标网格
* @param {Array} meshState 要恢复的网格状态
* @private
*/
_restoreMeshState(mesh, meshState) {
if (!mesh || !meshState || !Array.isArray(mesh) || !Array.isArray(meshState)) return;
for (let i = 0; i < Math.min(mesh.length, meshState.length); i++) {
for (let j = 0; j < Math.min(mesh[i].length, meshState[i].length); j++) {
const point = mesh[i][j];
const statePoint = meshState[i][j];
point.x = statePoint.x;
point.y = statePoint.y;
point.originalX = statePoint.originalX;
point.originalY = statePoint.originalY;
}
}
}
/**
* 克隆图像数据
* @param {ImageData} imageData 原始图像数据
* @returns {ImageData} 克隆的图像数据
* @private
*/
_cloneImageData(imageData) {
if (!imageData) return null;
try {
// 使用新的浏览器API直接复制
return new ImageData(
new Uint8ClampedArray(imageData.data),
imageData.width,
imageData.height
);
} catch (e) {
console.warn("使用备选方法克隆ImageData");
// 备选方法
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = imageData.width;
canvas.height = imageData.height;
ctx.putImageData(imageData, 0, 0);
return ctx.getImageData(0, 0, imageData.width, imageData.height);
}
}
}
/**
* 批量液化状态命令 - 用于处理多个对象的液化操作
*/
export class BatchLiquifyStateCommand extends Command {
/**
* 创建批量液化状态命令
* @param {Object} options 配置选项
* @param {Array} options.commands 液化状态命令列表
* @param {Object} options.canvas Fabric.js画布实例
*/
constructor(options) {
super({
name: options.name || "批量液化操作",
description: options.description || `批量液化${options.commands?.length || 0}个对象`,
});
this.commands = options.commands || [];
this.canvas = options.canvas;
this.refManager = getLiquifyReferenceManager();
}
/**
* 添加液化状态命令
* @param {LiquifyStateCommand} command 液化状态命令
*/
addCommand(command) {
this.commands.push(command);
}
/**
* 执行批量操作
*/
async execute() {
const results = [];
const updates = [];
// 准备批量更新数据
for (const command of this.commands) {
if (command.finalImageData && command.objectRefId) {
updates.push({
refId: command.objectRefId,
imageData: command.finalImageData,
});
}
}
// 执行批量更新
if (updates.length > 0) {
const updateResults = await this.refManager.batchUpdate(updates);
results.push(...updateResults);
}
// 更新命令状态
this.commands.forEach((command) => {
command.currentState = "final";
});
this.canvas.renderAll();
return results;
}
/**
* 撤销批量操作
*/
async undo() {
// 逆序撤销
for (let i = this.commands.length - 1; i >= 0; i--) {
await this.commands[i].undo();
}
this.canvas.renderAll();
return true;
}
/**
* 重做批量操作
*/
async redo() {
return this.execute();
}
/**
* 检查批量命令是否有效
* @returns {Boolean} 是否有效
*/
isValid() {
return this.commands.length > 0 && this.commands.every((cmd) => cmd.isValid());
}
/**
* 清理所有子命令的资源
*/
dispose() {
this.commands.forEach((command) => {
if (command.dispose) {
command.dispose();
}
});
}
}
/**
* 序列化fabric对象为JSON
* @param {Object} fabricObject fabric对象
* @returns {Object} 序列化后的对象状态
*/
export function serializeFabricObject(fabricObject) {
if (!fabricObject) {
throw new Error("无法序列化:对象为空");
}
try {
// 使用fabric.js的toObject方法序列化
const serializedObject = fabricObject.toObject([
"id",
"objectId",
"uid",
"layerId",
"name",
"type",
]);
// 记录额外的元数据
const metadata = {
timestamp: Date.now(),
objectType: fabricObject.type,
objectId: fabricObject.id || fabricObject.objectId || fabricObject.uid,
layerId: fabricObject.layerId,
bounds: fabricObject.getBoundingRect(),
};
return {
serializedObject,
metadata,
version: "1.0",
};
} catch (error) {
console.error("序列化fabric对象失败:", error);
throw error;
}
}
/**
* 辅助函数:创建液化状态命令
* @param {Object} options 配置选项
* @returns {LiquifyStateCommand} 状态命令实例
*/
export function createLiquifyStateCommand(options) {
return new LiquifyStateCommand(options);
}
/**
* 辅助函数:创建液化重置命令
* @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);
}