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

1239 lines
36 KiB
JavaScript
Raw Normal View History

2025-06-09 10:25:54 +08:00
import { Command, FunctionCommand } from "./Command";
2025-06-18 11:05:23 +08:00
import { getLiquifyReferenceManager } from "../managers/LiquifyReferenceManager";
2025-11-06 11:04:14 +08:00
import { optimizeCanvasRendering } from "../utils/helper";
2025-06-09 10:25:54 +08:00
/**
* 液化命令基类
* 所有液化相关命令的基类
*/
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 || "未知模式"}模式进行液化操作`,
2025-06-09 10:25:54 +08:00
});
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();
2025-11-06 11:04:14 +08:00
// 注意_updateObjectWithResult 内部已使用 optimizeCanvasRendering会自动渲染
2025-06-09 10:25:54 +08:00
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,
2025-06-09 10:25:54 +08:00
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);
2025-11-06 11:04:14 +08:00
// 使用优化渲染工具,避免图层闪烁
await optimizeCanvasRendering(this.canvas, async () => {
// 预先加载图像,确保完全加载后再替换
await new Promise((resolve, reject) => {
fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => {
if (!img) {
reject(new Error("图像加载失败"));
return;
2025-06-09 10:25:54 +08:00
}
2025-11-06 11:04:14 +08:00
// 保留原对象的属性
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,
});
// 确保图像已完全加载(通过检查元素)
if (img._element && img._element.complete) {
this._replaceObjectSafely(img);
resolve();
} else {
// 如果图像还未加载完成,等待加载
img.on("loaded", () => {
this._replaceObjectSafely(img);
resolve();
});
img.on("error", (error) => {
reject(error || new Error("图像加载失败"));
});
}
});
2025-06-09 10:25:54 +08:00
});
});
return true;
}
2025-11-06 11:04:14 +08:00
/**
* 安全地替换对象避免图层闪烁
* @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;
}
}
}
}
2025-06-09 10:25:54 +08:00
}
/**
* 液化工具初始化命令
* 用于初始化液化工具的状态不执行实际操作
*/
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 || "未知模式"}变形`,
2025-06-09 10:25:54 +08:00
});
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);
2025-11-06 11:04:14 +08:00
// 注意_updateObjectWithImageData 内部已使用 optimizeCanvasRendering会自动渲染
2025-06-09 10:25:54 +08:00
return this.afterData;
}
async undo() {
if (!this.beforeData) {
throw new Error("无法撤销:缺少变形前的数据");
}
// 恢复到变形前的状态
await this._updateObjectWithImageData(this.beforeData);
2025-11-06 11:04:14 +08:00
// 注意_updateObjectWithImageData 内部已使用 optimizeCanvasRendering会自动渲染
2025-06-09 10:25:54 +08:00
return true;
}
/**
* 使用图像数据更新对象
* @param {ImageData} imageData 图像数据
* @private
*/
async _updateObjectWithImageData(imageData) {
2025-11-06 11:04:14 +08:00
// 创建临时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 new Promise((resolve, reject) => {
fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => {
if (!img) {
reject(new Error("图像加载失败"));
return;
2025-06-09 10:25:54 +08:00
}
2025-11-06 11:04:14 +08:00
// 保留原对象的变换属性
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,
});
// 确保图像已完全加载
if (img._element && img._element.complete) {
this._replaceDeformObjectSafely(img);
resolve();
} else {
// 如果图像还未加载完成,等待加载
img.on("loaded", () => {
this._replaceDeformObjectSafely(img);
resolve();
});
img.on("error", (error) => {
reject(error || new Error("图像加载失败"));
});
}
});
2025-06-09 10:25:54 +08:00
});
});
}
2025-11-06 11:04:14 +08:00
/**
* 安全地替换变形对象避免图层闪烁
* @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;
}
}
}
}
2025-06-09 10:25:54 +08:00
}
/**
* 复合液化命令 - 用于组合多个液化操作
* 支持一次撤销多个相关的液化变形
*/
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}个液化操作`,
2025-06-09 10:25:54 +08:00
});
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;
}
}
2025-06-18 11:05:23 +08:00
/**
* 液化状态命令 - 最优化版本
* 使用引用管理器避免对象引用丢失支持高性能的状态管理
*/
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 最终图像数据
2025-06-29 23:29:47 +08:00
* @param {Object} options.liquifyManager 液化管理器实例
2025-06-18 11:05:23 +08:00
*/
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;
2025-06-29 23:29:47 +08:00
this.liquifyManager = options.liquifyManager; // 添加液化管理器引用
2025-06-18 11:05:23 +08:00
// 获取引用管理器实例
this.refManager = getLiquifyReferenceManager();
// 实时更新实例
this.realtimeUpdater = options.realtimeUpdater || null;
2025-06-18 11:05:23 +08:00
// 注册对象到引用管理器
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;
2025-06-29 23:29:47 +08:00
// 保存液化管理器的操作记录状态
this.initialLiquifyState = null;
this.finalLiquifyState = null;
2025-06-18 11:05:23 +08:00
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);
2025-06-18 11:05:23 +08:00
2025-06-29 23:29:47 +08:00
// 恢复液化管理器到最终状态
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();
}
}
2025-06-18 11:05:23 +08:00
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);
2025-06-18 11:05:23 +08:00
// 恢复液化管理器到初始状态 - 关键修复
2025-06-29 23:29:47 +08:00
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) {
2025-06-29 23:29:47 +08:00
const currentTarget = this.refManager.getObjectRef(this.objectRefId);
this.realtimeUpdater.targetObject = currentTarget;
// 重置实时更新器的内部状态
if (this.realtimeUpdater.reset) {
this.realtimeUpdater.reset();
2025-06-29 23:29:47 +08:00
}
}
}
2025-06-18 11:05:23 +08:00
this.currentState = "initial";
this.canvas.renderAll();
console.log("🔄 液化命令撤销完成,恢复初始状态(已重置所有内部状态)");
2025-06-18 11:05:23 +08:00
return true;
}
/**
* 重做命令 - 重新应用最终状态
*/
async redo() {
return this.execute();
}
/**
* 设置最终状态的图像数据
* @param {ImageData} finalImageData 最终状态的图像数据
*/
setFinalImageData(finalImageData) {
this.finalImageData = finalImageData;
this.finalSnapshotId = null; // 重置快照ID下次执行时重新创建
2025-06-29 23:29:47 +08:00
// 捕获当前液化管理器状态作为最终状态
if (this.liquifyManager) {
this.finalLiquifyState = this._captureLiquifyManagerState();
}
2025-06-18 11:05:23 +08:00
}
/**
* 获取当前状态标记
* @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) || {},
2025-06-18 11:05:23 +08:00
};
this.refManager.stateSnapshots.set(this.initialSnapshotId, snapshot);
2025-06-29 23:29:47 +08:00
// 捕获初始液化管理器状态
if (this.liquifyManager) {
this.initialLiquifyState = this._captureLiquifyManagerState();
}
2025-06-18 11:05:23 +08:00
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) || {},
2025-06-18 11:05:23 +08:00
};
this.refManager.stateSnapshots.set(this.finalSnapshotId, snapshot);
2025-06-29 23:29:47 +08:00
// 捕获最终液化管理器状态
if (this.liquifyManager) {
this.finalLiquifyState = this._captureLiquifyManagerState();
}
2025-06-18 11:05:23 +08:00
console.log(`📸 最终状态快照已创建: ${this.finalSnapshotId}`);
}
}
/**
2025-06-29 23:29:47 +08:00
* 捕获液化管理器的当前状态
* @returns {Object} 液化管理器状态
2025-06-18 11:05:23 +08:00
* @private
*/
2025-06-29 23:29:47 +08:00
_captureLiquifyManagerState() {
if (!this.liquifyManager) return null;
try {
const enhancedManager = this.liquifyManager.enhancedManager;
2025-06-29 23:29:47 +08:00
const state = {
// 捕获增强管理器状态
enhancedManagerState: null,
// 捕获当前渲染器状态
activeRendererState: null,
// 捕获目标对象引用
targetObjectRef: this.liquifyManager.targetObject ?? enhancedManager.targetObject,
2025-06-29 23:29:47 +08:00
// 捕获初始化状态
initialized: this.liquifyManager.initialized || false,
};
2025-06-18 11:05:23 +08:00
2025-06-29 23:29:47 +08:00
// 如果有增强管理器,捕获其状态
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,
2025-06-29 23:29:47 +08:00
// 保存变形历史
deformHistory: renderer.deformHistory ? [...renderer.deformHistory] : [],
2025-06-29 23:29:47 +08:00
};
}
}
console.log(`💾 液化管理器状态已捕获:`, state);
return state;
} catch (error) {
console.error("捕获液化管理器状态失败:", error);
return null;
2025-06-18 11:05:23 +08:00
}
2025-06-29 23:29:47 +08:00
}
/**
* 恢复液化管理器状态
* @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);
}
}
2025-06-29 23:29:47 +08:00
// 恢复增强管理器状态
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;
// 关键修复:确保图像数据被正确恢复
2025-06-29 23:29:47 +08:00
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;
// 关键修复:强制重置渲染器的图像数据
2025-06-29 23:29:47 +08:00
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
);
2025-06-29 23:29:47 +08:00
}
// 重置变形历史
2025-06-29 23:29:47 +08:00
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;
2025-06-29 23:29:47 +08:00
}
}
}
console.log(`🔄 液化管理器状态已恢复(包含完整的数据重置)`);
2025-06-29 23:29:47 +08:00
} catch (error) {
console.error("恢复液化管理器状态失败:", error);
2025-06-18 11:05:23 +08:00
}
2025-06-29 23:29:47 +08:00
}
/**
* 捕获网格状态
* @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,
}))
);
}
2025-06-18 11:05:23 +08:00
2025-06-29 23:29:47 +08:00
/**
* 恢复网格状态
* @param {Array} mesh 目标网格
* @param {Array} meshState 要恢复的网格状态
* @private
*/
_restoreMeshState(mesh, meshState) {
if (!mesh || !meshState || !Array.isArray(mesh) || !Array.isArray(meshState)) return;
2025-06-29 23:29:47 +08:00
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;
}
}
2025-06-18 11:05:23 +08:00
}
/**
* 克隆图像数据
* @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);
}
}
2025-06-18 11:05:23 +08:00
}
/**
* 批量液化状态命令 - 用于处理多个对象的液化操作
*/
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}个对象`,
2025-06-18 11:05:23 +08:00
});
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());
2025-06-18 11:05:23 +08:00
}
/**
* 清理所有子命令的资源
*/
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);
}
2025-06-09 10:25:54 +08:00
/**
* 辅助函数创建液化重置命令
* @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);
}