import { Command } from "./Command"; import { createLayer, LayerType, OperationType } from "../utils/layerHelper"; import { createStaticCanvas } from "../utils/canvasFactory"; import { AddObjectToLayerCommand } from "./ObjectLayerCommands"; import { ToolCommand } from "./ToolCommands"; /** * 添加图层命令 */ export class AddLayerCommand extends Command { constructor(options) { super({ name: "添加图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.newLayer = options.newLayer; this.activeLayerId = options.activeLayerId; this.insertIndex = options.insertIndex; this.oldActiveLayerId = null; this.beforeLayers = [...this.layers.value]; // 备份原图层列表 } execute() { // 保存当前活动图层ID this.oldActiveLayerId = this.activeLayerId.value; // 执行添加图层操作 if (this.insertIndex !== undefined && this.insertIndex !== null) { this.layers.value.splice(this.insertIndex, 0, this.newLayer); } else { this.layers.value.push(this.newLayer); } // 更新活动图层 if (!this.newLayer.isBackground) { this.activeLayerId.value = this.newLayer.id; } return this.newLayer.id; } undo() { // 从图层列表删除该图层 this.layers.value = this.beforeLayers; // 恢复原活动图层 this.activeLayerId.value = this.oldActiveLayerId; } getInfo() { return { name: this.name, layerName: this.newLayer.name, layerId: this.newLayer.id, }; } } /** * 粘贴并创建图层命令 - 更新为支持异步操作 */ export class PasteLayerCommand extends Command { constructor(options) { super({ name: "粘贴图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.activeLayerId = options.activeLayerId; this.clipboardData = options.clipboardData; this.layerManager = options.layerManager; // 新图层相关属性 this.newLayer = null; this.newLayerId = null; this.insertIndex = null; this.oldActiveLayerId = null; this.createdObjects = []; } async execute() { if (!this.clipboardData) { console.error("剪贴板中没有图层数据"); return null; } const data = this.clipboardData; const fabric = window.fabric; if (!fabric) { console.error("未找到fabric库"); return null; } // 生成新的图层ID this.newLayerId = `layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`; // 创建新图层 this.newLayer = { ...data, id: this.newLayerId, name: `${data.name} 副本`, fabricObjects: [], isCut: undefined, serializedObjects: undefined, }; // 保存当前活动图层ID this.oldActiveLayerId = this.activeLayerId.value; // 计算插入位置 this.insertIndex = this.layerManager._getInsertIndexAboveActiveLayer(); // 执行添加图层操作 if (this.insertIndex !== undefined && this.insertIndex !== null) { this.layers.value.splice(this.insertIndex, 0, this.newLayer); } else { this.layers.value.push(this.newLayer); } // 更新活动图层 if (!this.newLayer.isBackground) { this.activeLayerId.value = this.newLayer.id; } // 如果有序列化的对象,异步恢复它们 if ( data.serializedObjects && Array.isArray(data.serializedObjects) && data.serializedObjects.length > 0 ) { await this._restoreObjectsAsync(data); } else { this._onObjectsRestored(data); } return this.newLayerId; } /** * 异步恢复序列化的对象 * @param {Object} data 剪贴板数据 * @private */ async _restoreObjectsAsync(data) { const fabric = window.fabric; return new Promise((resolve, reject) => { fabric.util.enlivenObjects(data.serializedObjects, (objects) => { try { objects.forEach((obj) => { // 生成新的对象ID const newObjId = `obj_${Date.now()}_${Math.floor( Math.random() * 1000 )}`; obj.id = newObjId; obj.layerId = this.newLayerId; obj.layerName = this.newLayer.name; // 如果是复制操作,给对象添加偏移量 if (!data.isCut) { const offset = 10; if (obj.left !== undefined) obj.left += offset; if (obj.top !== undefined) obj.top += offset; } // 添加到画布 this.canvas.add(obj); // 添加到图层 this.newLayer.fabricObjects.push(obj); // 记录创建的对象,用于撤销 this.createdObjects.push(obj); }); this._onObjectsRestored(data); resolve(); } catch (error) { console.error("恢复对象时发生错误:", error); reject(error); } }); }); } /** * 对象恢复完成后的处理 * @param {Object} data 剪贴板数据 * @private */ _onObjectsRestored(data) { // 更新对象交互性 this.layerManager?.updateLayersObjectsInteractivity?.(); // 重新排列对象 this.layerManager?._rearrangeObjects?.(); // 判断如果是剪切操作,粘贴完后需要删除剪贴板数据 if (data.isCut && this.layerManager) { this.layerManager.clipboardData = null; console.log(`已粘贴图层:${this.newLayer.name}(剪切)`); } else { console.log(`已粘贴图层:${this.newLayer.name}(复制)`); } // 重新渲染画布 if (this.canvas) { this.canvas.renderAll(); } } undo() { if (!this.newLayer || !this.newLayerId) return; // 从图层列表删除该图层 const index = this.layers.value.findIndex( (layer) => layer.id === this.newLayerId ); if (index !== -1) { this.layers.value.splice(index, 1); } // 恢复原活动图层 this.activeLayerId.value = this.oldActiveLayerId; // 从画布移除所有创建的对象 this.createdObjects.forEach((obj) => { this.canvas.remove(obj); }); // 如果图层有其他fabric对象,也要移除 if (this.newLayer.fabricObjects && this.newLayer.fabricObjects.length > 0) { this.newLayer.fabricObjects.forEach((obj) => { if (!this.createdObjects.includes(obj)) { this.canvas.remove(obj); } }); } // 如果是剪切操作的撤销,需要恢复剪贴板数据 if (this.clipboardData && this.clipboardData.isCut && this.layerManager) { this.layerManager.clipboardData = this.clipboardData; } // 重新渲染画布 if (this.canvas) { this.canvas.renderAll(); } // 更新对象交互性 if ( this.layerManager && typeof this.layerManager.updateLayersObjectsInteractivity === "function" ) { this.layerManager.updateLayersObjectsInteractivity(); } } getInfo() { return { name: this.name, layerName: this.newLayer?.name || "未知图层", layerId: this.newLayerId, objectCount: this.createdObjects.length, }; } } /** * 移除图层命令 */ export class RemoveLayerCommand extends Command { constructor(options) { super({ name: "移除图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; this.activeLayerId = options.activeLayerId; // 查找要删除的图层 this.layerIndex = this.layers.value.findIndex( (layer) => layer.id === this.layerId ); this.removedLayer = this.layers.value[this.layerIndex]; this.isActiveLayer = this.layerId === this.activeLayerId.value; // this.beforeLayers = [...this.layers.value]; // 备份原图层列表 } execute() { if (this.layerIndex === -1 || !this.removedLayer) { console.error(`图层 ${this.layerId} 不存在`); return false; } // 从画布中移除图层中的所有对象 if ( this.removedLayer.fabricObjects && this.removedLayer.fabricObjects.length > 0 ) { this.removedLayer.fabricObjects.forEach((obj) => { this.canvas.remove(obj); }); } // 如果是背景图层,移除特殊对象 if (this.removedLayer.isBackground && this.removedLayer.fabricObject) { this.canvas.remove(this.removedLayer.fabricObject); } // 从图层列表中删除 this.layers.value.splice(this.layerIndex, 1); // 如果删除的是当前活动图层,需要更新活动图层 if (this.isActiveLayer) { // 查找最近的非背景层作为新的活动图层 const newActiveLayer = this.layers.value.find( (layer) => !layer.isBackground ); if (newActiveLayer) { this.activeLayerId.value = newActiveLayer.id; } else { this.activeLayerId.value = null; } } // 重新渲染画布 if (this.canvas) { this.canvas.renderAll(); } return true; } undo() { // 恢复图层 if (this.layerIndex !== -1 && this.removedLayer) { this.layers.value.splice(this.layerIndex, 0, this.removedLayer); // 恢复图层中的所有对象到画布 if ( this.removedLayer.fabricObjects && this.removedLayer.fabricObjects.length > 0 ) { this.removedLayer.fabricObjects.forEach((obj) => { this.canvas.add(obj); }); } // 如果是背景图层,恢复特殊对象 if (this.removedLayer.isBackground && this.removedLayer.fabricObject) { this.canvas.add(this.removedLayer.fabricObject); } // 如果删除的是当前活动图层,恢复活动图层 if (this.isActiveLayer) { this.activeLayerId.value = this.layerId; } // 重新渲染画布 if (this.canvas) { this.canvas.renderAll(); } } } getInfo() { return { name: this.name, layerName: this.removedLayer?.name || "未知图层", layerId: this.layerId, }; } } /** * 移动图层命令 */ export class MoveLayerCommand extends Command { constructor(options) { super({ name: `移动图层 ${options.direction === "up" ? "上移" : "下移"}`, saveState: false, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; this.direction = options.direction; // "up" or "down" // 查找图层索引 this.layerIndex = this.layers.value.findIndex( (layer) => layer.id === this.layerId ); // this.beforeLayers = [...this.layers.value]; // 备份原图层列表 } execute() { if (this.layerIndex === -1) { console.error(`图层 ${this.layerId} 不存在`); return false; } const layer = this.layers.value[this.layerIndex]; let newIndex = this.layerIndex; // 计算新索引 if (this.direction === "up") { // 向上移动(在数组中向前移动) if (this.layerIndex > 0) { // 确保不会移动到背景层之前 const prevLayer = this.layers.value[this.layerIndex - 1]; if (!prevLayer.isBackground) { newIndex = this.layerIndex - 1; } } } else if (this.direction === "down") { // 向下移动(在数组中向后移动) if (this.layerIndex < this.layers.value.length - 1) { // 确保不会移动背景层 if (!layer.isBackground) { newIndex = this.layerIndex + 1; } } } // 如果位置有变化,执行移动 if (newIndex !== this.layerIndex) { // 移除原位置 this.layers.value.splice(this.layerIndex, 1); // 插入到新位置 this.layers.value.splice(newIndex, 0, layer); this.newIndex = newIndex; return true; } return false; } undo() { if (this.layerIndex !== this.newIndex && this.newIndex !== undefined) { // 获取图层 const layer = this.layers.value[this.newIndex]; // 移除新位置 this.layers.value.splice(this.newIndex, 1); // 插入到原位置 this.layers.value.splice(this.layerIndex, 0, layer); } } getInfo() { return { name: this.name, layerId: this.layerId, direction: this.direction, }; } } /** * 切换图层可见性命令 */ export class ToggleLayerVisibilityCommand extends Command { constructor(options) { super({ name: "切换图层可见性", saveState: false, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; // 查找图层 this.layer = this.layers.value.find((layer) => layer.id === this.layerId); this.oldVisibility = this.layer ? this.layer.visible : null; } execute() { if (!this.layer) { console.error(`图层 ${this.layerId} 不存在`); return false; } // 切换可见性 this.layer.visible = !this.oldVisibility; // 更新画布上图层对象的可见性 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.visible = this.layer.visible; }); this.canvas.renderAll(); } return true; } undo() { if (this.layer) { // 恢复可见性 this.layer.visible = this.oldVisibility; // 更新画布上图层对象的可见性 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.visible = this.oldVisibility; }); this.canvas.renderAll(); } } } getInfo() { return { name: this.name, layerName: this.layer?.name || "未知图层", layerId: this.layerId, newVisibility: this.layer?.visible, }; } } /** * 重命名图层命令 */ export class RenameLayerCommand extends Command { constructor(options) { super({ name: "重命名图层", saveState: false, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; this.newName = options.newName; // 查找图层 this.layer = this.layers.value.find((layer) => layer.id === this.layerId); this.oldName = this.layer ? this.layer.name : null; } execute() { if (!this.layer) { console.error(`图层 ${this.layerId} 不存在`); return false; } // 更新图层名称 this.layer.name = this.newName; // 更新图层对象上的图层名称 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.layerName = this.newName; }); } return true; } undo() { if (this.layer && this.oldName) { // 恢复图层名称 this.layer.name = this.oldName; // 恢复图层对象上的图层名称 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.layerName = this.oldName; }); } } } getInfo() { return { name: this.name, layerId: this.layerId, oldName: this.oldName, newName: this.newName, }; } } /** * 图层锁定/解锁命令 */ export class LayerLockCommand extends Command { constructor(options) { super({ name: "图层锁定/解锁", saveState: false, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; // 查找图层 this.layer = this.layers.value.find((layer) => layer.id === this.layerId); this.oldLocked = this.layer ? this.layer.locked : null; } execute() { if (!this.layer) { console.error(`图层 ${this.layerId} 不存在`); return false; } // 切换锁定状态 this.layer.locked = !this.oldLocked; // 更新画布上对象的可选择状态 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.selectable = !this.layer.locked && this.layer.visible; obj.evented = !this.layer.locked && this.layer.visible; }); this.canvas.renderAll(); } return true; } undo() { if (this.layer) { // 恢复锁定状态 this.layer.locked = this.oldLocked; // 更新画布上对象的可选择状态 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.selectable = !this.oldLocked && this.layer.visible; obj.evented = !this.oldLocked && this.layer.visible; }); this.canvas.renderAll(); } } } getInfo() { return { name: this.name, layerName: this.layer?.name || "未知图层", layerId: this.layerId, newLocked: this.layer?.locked, }; } } /** * 设置图层不透明度命令 */ export class SetLayerOpacityCommand extends Command { constructor(options) { super({ name: "设置图层不透明度", saveState: false, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; this.opacity = options.opacity; // 查找图层 this.layer = this.layers.value.find((layer) => layer.id === this.layerId); this.oldOpacity = this.layer ? this.layer.opacity : null; } execute() { if (!this.layer) { console.error(`图层 ${this.layerId} 不存在`); return false; } // 设置图层不透明度 this.layer.opacity = this.opacity; // 更新画布上对象的不透明度 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.opacity = this.opacity; }); this.canvas.renderAll(); } return true; } undo() { if (this.layer && this.oldOpacity !== null) { // 恢复图层不透明度 this.layer.opacity = this.oldOpacity; // 更新画布上对象的不透明度 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.opacity = this.oldOpacity; }); this.canvas.renderAll(); } } } getInfo() { return { name: this.name, layerName: this.layer?.name || "未知图层", layerId: this.layerId, oldOpacity: this.oldOpacity, newOpacity: this.opacity, }; } } /** * 设置图层混合模式命令 */ export class SetLayerBlendModeCommand extends Command { constructor(options) { super({ name: "设置图层混合模式", saveState: false, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; this.blendMode = options.blendMode; // 查找图层 this.layer = this.layers.value.find((layer) => layer.id === this.layerId); this.oldBlendMode = this.layer ? this.layer.blendMode : null; } execute() { if (!this.layer) { console.error(`图层 ${this.layerId} 不存在`); return false; } // 设置图层混合模式 this.layer.blendMode = this.blendMode; // 更新画布上对象的混合模式 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.globalCompositeOperation = this.blendMode; }); this.canvas.renderAll(); } return true; } undo() { if (this.layer && this.oldBlendMode) { // 恢复图层混合模式 this.layer.blendMode = this.oldBlendMode; // 更新画布上对象的混合模式 if (this.canvas) { const layerObjects = this.canvas .getObjects() .filter((obj) => obj.layerId === this.layerId); layerObjects.forEach((obj) => { obj.globalCompositeOperation = this.oldBlendMode; }); this.canvas.renderAll(); } } } getInfo() { return { name: this.name, layerName: this.layer?.name || "未知图层", layerId: this.layerId, oldBlendMode: this.oldBlendMode, newBlendMode: this.blendMode, }; } } /** * 合并图层命令 */ export class MergeLayersCommand extends Command { constructor(options) { super({ name: "合并图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.layerIds = options.layerIds; this.newName = options.newName; this.activeLayerId = options.activeLayerId; // <--- 新增 // 备份原图层 this.originalLayers = [...this.layers.value]; // 新图层ID this.newLayerId = `merged_layer_${Date.now()}_${Math.floor( Math.random() * 1000 )}`; } execute() { if ( !this.layerIds || !Array.isArray(this.layerIds) || this.layerIds.length < 2 ) { console.error("合并图层至少需要两个图层"); return null; } // 查找所有要合并的图层 const layersToMerge = this.layerIds .map((id) => this.layers.value.find((layer) => layer.id === id)) .filter(Boolean); if (layersToMerge.length < 2) { console.error("找不到足够的图层进行合并"); return null; } // 检查是否包含背景图层 if (layersToMerge.some((layer) => layer.isBackground)) { console.error("不能合并背景图层"); return null; } // 查找最顶层图层的索引,用于插入合并后的图层 const topLayerIndex = Math.min( ...layersToMerge.map((layer) => this.layers.value.indexOf(layer)) ); // 获取要保留的所有对象 const allObjects = []; layersToMerge.forEach((layer) => { if (Array.isArray(layer.fabricObjects)) { allObjects.push(...layer.fabricObjects); } }); // 创建新的合并图层 const mergedLayer = createLayer({ id: this.newLayerId, name: this.newName || `合并图层`, type: LayerType.BITMAP, visible: true, locked: false, opacity: 1.0, fabricObjects: allObjects, }); // 更新对象与新图层的关联 allObjects.forEach((obj) => { obj.layerId = mergedLayer.id; obj.layerName = mergedLayer.name; }); // 移除原图层 this.layers.value = this.layers.value.filter( (layer) => !this.layerIds.includes(layer.id) ); // 插入新图层 this.layers.value.splice(topLayerIndex, 0, mergedLayer); // 更新当前活动图层 this.activeLayerId.value = this.newLayerId; // 重新渲染画布 if (this.canvas) { this.canvas.renderAll(); } return this.newLayerId; } undo() { // 恢复原始图层状态 this.layers.value = [...this.originalLayers]; // 恢复活动图层 if (this.activeLayerId) { // 恢复到合并前的活动图层(取第一个合并前图层) this.activeLayerId.value = this.layerIds[0]; } // 重新渲染画布 if (this.canvas) { this.canvas.renderAll(); } } getInfo() { return { name: this.name, layerIds: this.layerIds, newLayerId: this.newLayerId, newName: this.newName, }; } } /** * 图层组合命令 */ export class GroupLayersCommand extends Command { constructor(options) { super({ name: "组合图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.layerIds = options.layerIds; this.groupName = options.groupName; this.activeLayerId = options.activeLayerId; // <--- 新增 // 备份原图层 this.originalLayers = [...this.layers.value]; // 新组ID this.groupId = `group_layer_${Date.now()}_${Math.floor( Math.random() * 1000 )}`; } execute() { if ( !this.layerIds || !Array.isArray(this.layerIds) || this.layerIds.length < 2 ) { console.error("组合图层至少需要两个图层"); return null; } // 查找所有要组合的图层 const layersToGroup = this.layerIds .map((id) => this.layers.value.find((layer) => layer.id === id)) .filter(Boolean); if (layersToGroup.length < 2) { console.error("找不到足够的图层进行组合"); return null; } // 检查是否包含背景图层 if (layersToGroup.some((layer) => layer.isBackground)) { console.error("不能组合背景图层"); return null; } // 查找最顶层图层的索引,用于插入组图层 const topLayerIndex = Math.min( ...layersToGroup.map((layer) => this.layers.value.indexOf(layer)) ); // 创建新的组图层 const groupLayer = createLayer({ id: this.groupId, name: this.groupName || `图层组`, type: LayerType.GROUP, visible: true, locked: false, opacity: 1.0, fabricObjects: [], children: layersToGroup, }); // 移除原图层 this.layers.value = this.layers.value.filter( (layer) => !this.layerIds.includes(layer.id) ); // 插入新组图层 this.layers.value.splice(topLayerIndex, 0, groupLayer); // 更新当前活动图层 this.activeLayerId.value = this.groupId; return this.groupId; } undo() { // 恢复原始图层状态 this.layers.value = [...this.originalLayers]; // 恢复活动图层为原先第一个合并前层 if (this.activeLayerId) { this.activeLayerId.value = this.layerIds[0]; } } getInfo() { return { name: this.name, layerIds: this.layerIds, groupId: this.groupId, groupName: this.groupName, }; } } /** * 解组图层命令 */ export class UngroupLayersCommand extends Command { constructor(options) { super({ name: "解组图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.groupId = options.groupId; this.activeLayerId = options.activeLayerId; // <--- 新增 // 备份原图层 this.originalLayers = [...this.layers.value]; // 子图层ID列表 this.childLayerIds = []; } execute() { // 查找组图层 const groupIndex = this.layers.value.findIndex( (layer) => layer.id === this.groupId ); if (groupIndex === -1) { console.error(`找不到组图层 ${this.groupId}`); return null; } const groupLayer = this.layers.value[groupIndex]; if (!groupLayer.children || groupLayer.children.length === 0) { console.error(`组图层 ${this.groupId} 没有子图层`); return null; } // 收集子图层ID this.childLayerIds = groupLayer.children.map((layer) => layer.id); // 将子图层添加到原位置 this.layers.value.splice(groupIndex, 1, ...groupLayer.children); // 更新当前活动图层为第一个子图层 if (this.childLayerIds.length > 0 && this.activeLayerId) { this.activeLayerId.value = this.childLayerIds[0]; } return this.childLayerIds; } undo() { // 恢复原始图层状态 this.layers.value = [...this.originalLayers]; // 恢复活动图层为原始组ID if (this.activeLayerId) { this.activeLayerId.value = this.groupId; } } getInfo() { return { name: this.name, groupId: this.groupId, childLayerIds: this.childLayerIds, }; } } /** * 合并图层内对象命令(重构版本) * 将新的图像与图层内现有对象合并为一个高保真图像对象 */ export class MergeLayerObjectsCommand extends Command { constructor(options) { super({ name: "合并图层内对象", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.fabricImage = options.fabricImage; this.activeLayer = options.activeLayer; // 备份原始对象,用于撤销 if (this.activeLayer && Array.isArray(this.activeLayer.fabricObjects)) { this.originalObjects = this.canvas ?.getObjects() ?.filter((fItem) => fItem.layerId === this.activeLayer.id) || []; } else { this.originalObjects = []; } // 新合并图像对象 this.mergedImage = null; this.newImageId = `merged_image_${Date.now()}_${Math.floor( Math.random() * 1000 )}`; } async execute() { if (!this.activeLayer || !this.canvas) { console.error("图层或Canvas未初始化"); return null; } // 获取所有需要合并的对象(按正确的层级顺序) const objectsToMerge = []; // 先添加图层中的现有对象(作为底层) if (this.originalObjects.length > 0) { objectsToMerge.push(...this.originalObjects); } // 再添加新的图像对象(作为顶层) if (this.fabricImage) { objectsToMerge.push(this.fabricImage); } if (objectsToMerge.length === 0) { console.log("没有对象需要合并"); return null; } // 计算所有对象的合并边界 const bounds = this._calculateMergedBounds(objectsToMerge); if (!bounds) { console.error("无法计算合并边界"); return null; } // 异步处理图像合并 try { const mergedImage = await this._createMergedImageAsync( objectsToMerge, bounds ); this._setupMergedImage(mergedImage, bounds); this._replaceObjects(mergedImage); console.log("图像合并完成"); return this.newImageId; } catch (error) { console.error("图像合并执行失败:", error); return null; } } /** * 异步创建合并图像 * @param {Array} objectsToMerge 要合并的对象 * @param {Object} bounds 边界信息 * @returns {Promise} 合并后的图像 * @private */ async _createMergedImageAsync(objectsToMerge, bounds) { return new Promise((resolve, reject) => { try { // 创建高保真临时画布 const tempCanvas = this._createHighQualityTempCanvas(bounds); const tempFabricCanvas = createStaticCanvas(tempCanvas, { width: bounds.width, height: bounds.height, }); // 设置高质量渲染选项 tempFabricCanvas.enableRetinaScaling = true; tempFabricCanvas.imageSmoothingEnabled = true; // 将所有对象添加到临时画布并调整位置 this._addObjectsToTempCanvas(tempFabricCanvas, objectsToMerge, bounds); // 渲染临时画布 tempFabricCanvas.renderAll(); // 生成高质量图像 const dataUrl = tempFabricCanvas.toDataURL({ format: "png", quality: 1.0, multiplier: 1, }); // 创建新的合并图像 fabric.Image.fromURL( dataUrl, (mergedImg) => { try { // 清理临时资源 this._cleanupTempCanvas(tempFabricCanvas); resolve(mergedImg); } catch (error) { console.error("设置合并图像时发生错误:", error); this._cleanupTempCanvas(tempFabricCanvas); reject(error); } }, { crossOrigin: "anonymous", } ); } catch (error) { console.error("合并过程中发生错误:", error); reject(error); } }); } /** * 计算所有对象的合并边界 * @param {Array} objects 要合并的对象数组 * @returns {Object} 边界信息 * @private */ _calculateMergedBounds(objects) { if (!objects || objects.length === 0) return null; let minLeft = Infinity; let minTop = Infinity; let maxRight = -Infinity; let maxBottom = -Infinity; objects.forEach((obj) => { if (!obj) return; const bounds = obj.getBoundingRect(true, true); minLeft = Math.min(minLeft, bounds.left); minTop = Math.min(minTop, bounds.top); maxRight = Math.max(maxRight, bounds.left + bounds.width); maxBottom = Math.max(maxBottom, bounds.top + bounds.height); }); const padding = 1; return { left: minLeft - padding, top: minTop - padding, width: maxRight - minLeft + padding * 2, height: maxBottom - minTop + padding * 2, }; } /** * 创建高质量临时画布 * @param {Object} bounds 边界信息 * @returns {HTMLCanvasElement} 临时画布 * @private */ _createHighQualityTempCanvas(bounds) { const tempCanvas = document.createElement("canvas"); tempCanvas.width = Math.ceil(bounds.width); tempCanvas.height = Math.ceil(bounds.height); tempCanvas.style.width = bounds.width + "px"; tempCanvas.style.height = bounds.height + "px"; const ctx = tempCanvas.getContext("2d"); ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = "high"; return tempCanvas; } /** * 将对象添加到临时画布并调整位置 * @param {fabric.Canvas} tempCanvas 临时画布 * @param {Array} objects 对象数组 * @param {Object} bounds 边界信息 * @private */ _addObjectsToTempCanvas(tempCanvas, objects, bounds) { objects.forEach((obj, index) => { if (!obj) return; try { const clonedObj = fabric.util.object.clone(obj); const objBounds = obj.getBoundingRect(true, true); const offsetX = objBounds.left - bounds.left; const offsetY = objBounds.top - bounds.top; clonedObj.set({ left: offsetX + (clonedObj.width * clonedObj.scaleX) / 2, top: offsetY + (clonedObj.height * clonedObj.scaleY) / 2, originX: "center", originY: "center", }); tempCanvas.add(clonedObj); console.log( `添加对象 ${index + 1}/${objects.length}: ${obj.type || "unknown"}` ); } catch (error) { console.error(`添加对象到临时画布时发生错误:`, error); } }); } /** * 设置合并后的图像属性 * @param {fabric.Image} mergedImg 合并后的图像 * @param {Object} bounds 边界信息 * @private */ _setupMergedImage(mergedImg, bounds) { mergedImg.set({ id: this.newImageId, layerId: this.activeLayer.id, layerName: this.activeLayer.name, left: bounds.left + bounds.width / 2, top: bounds.top + bounds.height / 2, originX: "center", originY: "center", selectable: true, evented: true, }); this.mergedImage = mergedImg; } /** * 替换原有对象为合并后的图像 * @param {fabric.Image} mergedImg 合并后的图像 * @private */ _replaceObjects(mergedImg) { if (!mergedImg || !this.canvas || !this.activeLayer) { console.error("_replaceObjects: 缺少必要的参数"); return; } const wasRenderOnAddRemove = this.canvas.renderOnAddRemove; this.canvas.renderOnAddRemove = false; try { // 清空图层的对象列表 this.activeLayer.fabricObjects = []; // 添加合并后的图像到画布和图层 this.canvas.add(mergedImg); this.activeLayer.fabricObjects.push(mergedImg); // 从画布中移除所有原始对象 this.originalObjects.forEach((obj) => { if (obj && this.canvas.getObjects().includes(obj)) { this.canvas.remove(obj); } }); // 如果有新的图像对象,也要移除 if ( this.fabricImage && this.canvas.getObjects().includes(this.fabricImage) ) { this.canvas.remove(this.fabricImage); } console.log( `成功替换图层 ${this.activeLayer.name} 中的 ${this.originalObjects.length} 个对象为合并图像` ); } catch (error) { console.error("替换对象时发生错误:", error); } finally { this.canvas.renderOnAddRemove = wasRenderOnAddRemove; this.canvas.renderAll(); // 同步渲染画布 // 更新缩略图 if (this.canvas.thumbnailManager) { setTimeout(() => { this.canvas.thumbnailManager.generateLayerThumbnail( this.activeLayer.id ); }, 100); } } } undo() { if (!this.activeLayer || !this.canvas) return; const wasRenderOnAddRemove = this.canvas.renderOnAddRemove; this.canvas.renderOnAddRemove = false; try { // 移除合并后的图像 if (this.mergedImage) { this.canvas.remove(this.mergedImage); const imageIndex = this.activeLayer.fabricObjects.findIndex( (obj) => obj.id === this.newImageId ); if (imageIndex !== -1) { this.activeLayer.fabricObjects.splice(imageIndex, 1); } } // 按原始顺序恢复对象到画布 this.originalObjects.forEach((obj) => { if (obj) { this.canvas.add(obj); } }); // 恢复图层对象列表 this.activeLayer.fabricObjects = [...this.originalObjects]; console.log(`成功撤销图层 ${this.activeLayer.name} 的对象合并操作`); } catch (error) { console.error("撤销合并操作时发生错误:", error); } finally { this.canvas.renderOnAddRemove = wasRenderOnAddRemove; this.canvas.renderAll(); // 更新缩略图 if (this.canvas.thumbnailManager) { setTimeout(() => { this.canvas.thumbnailManager.generateLayerThumbnail( this.activeLayer.id ); }, 100); } } } /** * 安全地清理临时画布资源 * @param {fabric.Canvas} tempCanvas 临时画布 * @private */ _cleanupTempCanvas(tempCanvas) { if (!tempCanvas) return; try { tempCanvas.clear(); const objects = tempCanvas.getObjects(); objects.forEach((obj) => { tempCanvas.remove(obj); }); const canvasEl = tempCanvas.getElement(); if (canvasEl && canvasEl.getContext) { const ctx = canvasEl.getContext("2d"); if (ctx) { ctx.clearRect(0, 0, canvasEl.width, canvasEl.height); } } if (typeof tempCanvas.destroy === "function") { tempCanvas.destroy(); } if (canvasEl && canvasEl.parentNode) { canvasEl.parentNode.removeChild(canvasEl); } console.log("临时画布资源已安全清理"); } catch (error) { console.warn("清理临时画布时发生警告:", error); } } getInfo() { return { name: this.name, layerId: this.activeLayer?.id, layerName: this.activeLayer?.name || "未知图层", originalObjectCount: this.originalObjects.length, hasNewImage: !!this.fabricImage, mergedImageId: this.newImageId, }; } } /** * 合并图层内对象成组的命令 * 将新的图像与图层内现有对象合并为一个组对象 * 支持向现有组添加对象,以及移除空组 */ export class LayerObjectsToGroupCommand extends Command { constructor(options) { super({ name: "图层内对象合并为组", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.fabricImage = options.fabricImage; this.activeLayer = options.activeLayer; // 备份原始对象,用于撤销 if (this.activeLayer && Array.isArray(this.activeLayer.fabricObjects)) { this.originalObjects = this.canvas ?.getObjects() ?.filter((fItem) => fItem.layerId === this.activeLayer.id) || []; } else { this.originalObjects = []; } // 组对象相关 this.existingGroup = null; // 现有的组对象 this.groupObject = null; // 最终的组对象(可能是现有的或新创建的) this.newGroupId = `group_${Date.now()}_${Math.floor(Math.random() * 1000)}`; this.wasGroupCreated = false; // 是否创建了新组 this.addedObjectsToGroup = []; // 添加到组中的新对象 this.originalLayerObjects = [...(this.activeLayer.fabricObjects || [])]; // 备份图层原始对象列表 } async execute() { if (!this.activeLayer || !this.canvas) { console.error("图层或Canvas未初始化"); return null; } // 查找图层中是否已有组对象 this.existingGroup = this._findExistingGroup(); // 准备要添加的新对象 const newObjectsToAdd = []; if (this.fabricImage) { newObjectsToAdd.push(this.fabricImage); } if (newObjectsToAdd.length === 0) { console.log("没有新对象需要添加到组"); return this.existingGroup?.id || null; } try { // 暂时禁用画布自动渲染 const wasRenderOnAddRemove = this.canvas.renderOnAddRemove; this.canvas.renderOnAddRemove = false; if (this.existingGroup) { // 如果已有组,将新对象添加到现有组中 this.groupObject = this.existingGroup; this._addObjectsToExistingGroup(newObjectsToAdd); console.log(`✅ 将 ${newObjectsToAdd.length} 个对象添加到现有组中`); } else { // 如果没有组,创建新组 this._createNewGroupWithAllObjects(newObjectsToAdd); this.wasGroupCreated = true; console.log( `✅ 创建新组并添加 ${ this.originalObjects.length + newObjectsToAdd.length } 个对象` ); } // 恢复画布自动渲染并重新渲染 this.canvas.renderOnAddRemove = wasRenderOnAddRemove; this.canvas.renderAll(); // 选中组对象 // this.canvas.setActiveObject(this.groupObject); // 更新缩略图 this._updateThumbnail(); return this.groupObject.id; } catch (error) { console.error("执行组合操作时发生错误:", error); return null; } } /** * 查找图层中现有的组对象 * @returns {fabric.Group|null} * @private */ _findExistingGroup() { if (!this.activeLayer.fabricObjects) return null; return ( this.activeLayer.fabricObjects.find( (obj) => obj && obj.type === "group" ) || null ); } /** * 将新对象添加到现有组中 * @param {Array} newObjects 要添加的新对象 * @private */ _addObjectsToExistingGroup(newObjects) { // 先从画布移除新对象(避免重复添加) newObjects.forEach((obj) => { if (this.canvas.getObjects().includes(obj)) { this.canvas.remove(obj); } }); // 使用 addWithUpdate 方法正确添加对象到组 newObjects.forEach((obj) => { this.existingGroup.addWithUpdate(obj); }); // 记录添加的对象,用于撤销 this.addedObjectsToGroup = newObjects; // 组对象引用不变,只是内容更新了 this.groupObject = this.existingGroup; } /** * 创建包含所有对象的新组 * @param {Array} newObjects 新添加的对象 * @private */ _createNewGroupWithAllObjects(newObjects) { const allObjects = [...this.originalObjects, ...newObjects]; // 从画布中移除所有要组合的对象 allObjects.forEach((obj) => { if (obj && this.canvas.getObjects().includes(obj)) { this.canvas.remove(obj); } }); // 创建组对象 - Fabric.js 5 中创建组时会自动将对象从画布移除 // 不需要手动从画布中移除对象 this.groupObject = new fabric.Group(allObjects, { id: this.newGroupId, layerId: this.activeLayer.id, layerName: this.activeLayer.name, selectable: true, evented: true, }); // 添加组对象到画布 this.canvas.add(this.groupObject); // 更新图层的对象列表 - 只包含组对象 this.activeLayer.fabricObjects = [this.groupObject]; // 记录添加的对象 this.addedObjectsToGroup = newObjects; } undo() { if (!this.activeLayer || !this.canvas || !this.groupObject) return; try { // 暂时禁用画布自动渲染 const wasRenderOnAddRemove = this.canvas.renderOnAddRemove; this.canvas.renderOnAddRemove = false; if (this.wasGroupCreated) { // 如果是新创建的组,完全撤销到原始状态 this._undoNewGroupCreation(); } else { // 如果是向现有组添加对象,只移除新添加的对象 this._undoAddToExistingGroup(); } // 恢复画布自动渲染并重新渲染 this.canvas.renderOnAddRemove = wasRenderOnAddRemove; this.canvas.renderAll(); // 更新缩略图 this._updateThumbnail(); console.log(`↩️ 成功撤销图层 ${this.activeLayer.name} 的对象组合操作`); } catch (error) { console.error("撤销组合操作时发生错误:", error); } } /** * 撤销新组的创建 * @private */ _undoNewGroupCreation() { // 从画布中移除组对象 if (this.canvas.getObjects().includes(this.groupObject)) { this.canvas.remove(this.groupObject); } // 解散组 - 使用 destroy 方法或直接处理 if (typeof this.groupObject.destroy === "function") { this.groupObject?.destroy?.(); } // 将原始对象重新添加到画布 // 注意:解散组后,对象会自动恢复到画布上,但需要重新设置属性 this.originalObjects.forEach((obj) => { if (obj && !this.canvas.getObjects().includes(obj)) { // 恢复对象的原始属性 obj.layerId = this.activeLayer.id; obj.layerName = this.activeLayer.name; this.canvas.add(obj); } }); // 恢复图层对象列表 this.activeLayer.fabricObjects = [...this.originalObjects]; } /** * 撤销向现有组添加对象的操作 * @private */ _undoAddToExistingGroup() { // 使用 removeWithUpdate 方法从组中移除新添加的对象 // 在 Fabric.js 5 中,removeWithUpdate 会自动将对象重新添加到画布 this.addedObjectsToGroup.forEach((obj) => { this.existingGroup.removeWithUpdate(obj); // 重新设置对象的图层关联 obj.layerId = this.activeLayer.id; obj.layerName = this.activeLayer.name; // 确保对象在图层对象列表中 if (!this.activeLayer.fabricObjects.includes(obj)) { this.activeLayer.fabricObjects.push(obj); } }); // 检查组是否变为空或只有一个对象 const remainingObjects = this.existingGroup.getObjects(); if (remainingObjects.length === 0) { // 组为空,移除组 this.canvas.remove(this.existingGroup); const groupIndex = this.activeLayer.fabricObjects.indexOf( this.existingGroup ); if (groupIndex !== -1) { this.activeLayer.fabricObjects.splice(groupIndex, 1); } } else if (remainingObjects.length === 1) { // 只剩一个对象,解散组 const singleObj = remainingObjects[0]; // 从画布移除组 this.canvas.remove(this.existingGroup); // 使用 removeWithUpdate 移除最后一个对象 // 这会自动将对象添加回画布 this.existingGroup.removeWithUpdate(singleObj); // 重新设置对象属性 singleObj.layerId = this.activeLayer.id; singleObj.layerName = this.activeLayer.name; // 更新图层对象列表 const groupIndex = this.activeLayer.fabricObjects.indexOf( this.existingGroup ); if (groupIndex !== -1) { this.activeLayer.fabricObjects[groupIndex] = singleObj; } } } /** * 更新缩略图 * @private */ _updateThumbnail() { if (this.canvas.thumbnailManager) { setTimeout(() => { this.canvas.thumbnailManager.generateLayerThumbnail( this.activeLayer.id ); }, 100); } } getInfo() { return { name: this.name, layerId: this.activeLayer?.id, layerName: this.activeLayer?.name || "未知图层", originalObjectCount: this.originalObjects.length, hasNewImage: !!this.fabricImage, groupId: this.groupObject?.id, wasGroupCreated: this.wasGroupCreated, addedObjectsCount: this.addedObjectsToGroup.length, }; } } /** * 创建图片图层复合命令 * 包含创建图层、添加对象到图层、切换工具等操作的复合命令 */ export class CreateImageLayerCommand extends Command { constructor(options) { super({ name: "创建图片图层", saveState: true, }); this.layerManager = options.layerManager; this.fabricImage = options.fabricImage; this.toolManager = options.toolManager; this.layerName = options.layerName || null; // 存储执行过程中的结果 this.newLayerId = null; this.commands = []; this.executedCommands = []; } async execute() { if (!this.layerManager || !this.fabricImage) { throw new Error("图层管理器或图片对象无效"); } try { this.commands = []; this.executedCommands = []; // 生成图层名称 const fileName = this.layerName || `图片 ${new Date().toLocaleTimeString()}`; // 1. 创建新图层命令 const createLayerCmd = new AddLayerCommand({ canvas: this.layerManager.canvas, layers: this.layerManager.layers, newLayer: createLayer({ name: fileName, type: LayerType.BITMAP, visible: true, locked: false, opacity: 1.0, fabricObjects: [], }), activeLayerId: this.layerManager.activeLayerId, insertIndex: this.layerManager._getInsertIndexAboveActiveLayer(), }); // 执行创建图层命令 this.newLayerId = await createLayerCmd.execute(); this.commands.push(createLayerCmd); this.executedCommands.push(createLayerCmd); // 2. 添加图片对象到图层命令 const addObjectCmd = new AddObjectToLayerCommand({ canvas: this.layerManager.canvas, layers: this.layerManager.layers, layerId: this.newLayerId, fabricObject: this.fabricImage, }); // 执行添加对象命令 await addObjectCmd.execute(); this.commands.push(addObjectCmd); this.executedCommands.push(addObjectCmd); // 3. 切换工具到选择模式命令 if (this.toolManager) { const toolCmd = new ToolCommand({ toolManager: this.toolManager, tool: OperationType.SELECT, previousTool: this.toolManager.getCurrentTool(), }); // 执行工具切换命令 await toolCmd.execute(); this.commands.push(toolCmd); this.executedCommands.push(toolCmd); } console.log(`✅ 创建图片图层完成: ${fileName}, ID: ${this.newLayerId}`); return this.newLayerId; } catch (error) { console.error("创建图片图层失败:", error); // 回滚已执行的命令 await this._rollbackExecutedCommands(); throw error; } } async undo() { if (this.executedCommands.length === 0) { console.warn("没有已执行的命令需要撤销"); return true; } console.log( `↩️ 开始撤销创建图片图层操作,共 ${this.executedCommands.length} 个子命令` ); try { // 逆序撤销已执行的命令 const commands = [...this.executedCommands].reverse(); for (const command of commands) { if (typeof command.undo === "function") { try { console.log(`↩️ 撤销子命令: ${command.constructor.name}`); const result = command.undo(); if (this._isPromise(result)) { await result; } console.log(`✅ 子命令撤销成功: ${command.constructor.name}`); } catch (error) { console.error( `❌ 子命令撤销失败: ${command.constructor.name}`, error ); } } } this.executedCommands = []; console.log(`✅ 创建图片图层撤销完成`); return true; } catch (error) { console.error("❌ 撤销创建图片图层过程中发生错误:", error); throw error; } } /** * 回滚已执行的命令(内部使用) * @private */ async _rollbackExecutedCommands() { console.log(`🔄 开始回滚已执行的 ${this.executedCommands.length} 个子命令`); const commands = [...this.executedCommands].reverse(); for (const command of commands) { if (typeof command.undo === "function") { try { console.log(`🔄 回滚子命令: ${command.constructor.name}`); const result = command.undo(); if (this._isPromise(result)) { await result; } console.log(`✅ 子命令回滚成功: ${command.constructor.name}`); } catch (error) { console.error( `❌ 子命令回滚失败: ${command.constructor.name}`, error ); } } } this.executedCommands = []; console.log(`✅ 回滚完成`); } /** * 检查返回值是否为Promise * @private */ _isPromise(value) { return ( value && typeof value === "object" && typeof value.then === "function" && typeof value.catch === "function" ); } getInfo() { return { name: this.name, layerName: this.layerName, layerId: this.newLayerId, commandCount: this.commands.length, executedCount: this.executedCommands.length, }; } } /** * 图层重新排序命令 */ export class ReorderLayersCommand extends Command { constructor(options) { super({ name: "图层重新排序", saveState: false, }); this.layers = options.layers; this.oldIndex = options.oldIndex; this.newIndex = options.newIndex; this.layerId = options.layerId; // 验证参数 if (this.oldIndex === undefined || this.newIndex === undefined) { throw new Error("缺少必要的索引参数"); } if (this.oldIndex === this.newIndex) { console.warn("新旧索引相同,无需排序"); } } execute() { if ( !this.layers || !this.layers.value || !Array.isArray(this.layers.value) ) { console.error("图层数组无效"); return false; } if (this.oldIndex < 0 || this.oldIndex >= this.layers.value.length) { console.error("原始索引超出范围"); return false; } if (this.newIndex < 0 || this.newIndex >= this.layers.value.length) { console.error("目标索引超出范围"); return false; } // 获取要移动的图层 const layerToMove = this.layers.value[this.oldIndex]; if (!layerToMove) { console.error("找不到要移动的图层"); return false; } // 验证图层ID是否匹配 if (this.layerId && layerToMove.id !== this.layerId) { console.error("图层ID不匹配"); return false; } // 执行重新排序 this.layers.value.splice(this.oldIndex, 1); this.layers.value.splice(this.newIndex, 0, layerToMove); console.log( `✅ 图层 "${layerToMove.name}" 从索引 ${this.oldIndex} 移动到 ${this.newIndex}` ); return true; } undo() { if ( !this.layers || !this.layers.value || !Array.isArray(this.layers.value) ) { console.error("图层数组无效"); return false; } if (this.newIndex < 0 || this.newIndex >= this.layers.value.length) { console.error("当前索引超出范围"); return false; } // 获取当前在新位置的图层 const layerToRestore = this.layers.value[this.newIndex]; if (!layerToRestore) { console.error("找不到要恢复的图层"); return false; } // 验证图层ID是否匹配 if (this.layerId && layerToRestore.id !== this.layerId) { console.error("图层ID不匹配"); return false; } // 恢复原始排序 this.layers.value.splice(this.newIndex, 1); this.layers.value.splice(this.oldIndex, 0, layerToRestore); console.log( `↩️ 图层 "${layerToRestore.name}" 恢复到原始位置 ${this.oldIndex}` ); return true; } getInfo() { return { name: this.name, layerId: this.layerId, oldIndex: this.oldIndex, newIndex: this.newIndex, }; } } /** * 子图层重新排序命令 */ export class ReorderChildLayersCommand extends Command { constructor(options) { super({ name: "子图层重新排序", saveState: false, }); this.layers = options.layers; this.parentId = options.parentId; this.oldIndex = options.oldIndex; this.newIndex = options.newIndex; this.layerId = options.layerId; } execute() { // 查找父图层 const parentLayer = this.layers.value.find( (layer) => layer.id === this.parentId ); if (!parentLayer || !parentLayer.children) { console.error("找不到父图层或父图层没有子图层"); return false; } // 执行重新排序 const childToMove = parentLayer.children[this.oldIndex]; parentLayer.children.splice(this.oldIndex, 1); parentLayer.children.splice(this.newIndex, 0, childToMove); return true; } undo() { // 查找父图层 const parentLayer = this.layers.value.find( (layer) => layer.id === this.parentId ); if (!parentLayer || !parentLayer.children) { return false; } // 恢复原始排序 const childToRestore = parentLayer.children[this.newIndex]; parentLayer.children.splice(this.newIndex, 1); parentLayer.children.splice(this.oldIndex, 0, childToRestore); return true; } getInfo() { return { name: this.name, parentId: this.parentId, layerId: this.layerId, oldIndex: this.oldIndex, newIndex: this.newIndex, }; } } /** * 更改固定图层图像命令 * 用于更换固定图层(红绿图模式、模特图层等)的图像内容 */ export class ChangeFixedImageCommand extends Command { constructor(options) { super({ name: "更改固定图层图像", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; this.newImageFile = options.newImageFile; this.layerManager = options.layerManager; // 备份原始数据 this.originalLayer = null; this.originalObject = null; this.newImageObject = null; } async execute() { if (!this.canvas || !this.layers || !this.layerId || !this.newImageFile) { throw new Error("更改固定图层图像命令缺少必要参数"); } // 查找目标固定图层 this.originalLayer = this.layers.value.find( (layer) => layer.id === this.layerId ); if (!this.originalLayer) { throw new Error(`找不到图层 ID: ${this.layerId}`); } // 验证是否为固定图层 if (!this.originalLayer.isFixed && !this.originalLayer.isBackground) { throw new Error("只能更改固定图层或背景图层的图像"); } // 备份原始对象 if (this.originalLayer.fabricObject) { this.originalObject = this.originalLayer.fabricObject; } // 创建新的图像对象 this.newImageObject = await this._createImageFromFile(this.newImageFile); // 设置新图像的属性 this._setupNewImageProperties(); // 替换图层中的对象 this._replaceLayerObject(); // 重新渲染画布 this.canvas.renderAll(); console.log(`✅ 成功更改固定图层 "${this.originalLayer.name}" 的图像`); return this.newImageObject.id; } /** * 从文件创建图像对象 * @param {File} file 图像文件 * @returns {Promise} 图像对象 * @private */ async _createImageFromFile(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { fabric.Image.fromURL( e.target.result, (img) => { if (!img) { reject(new Error("无法创建图像对象")); return; } resolve(img); }, { crossOrigin: "anonymous", } ); }; reader.onerror = () => reject(new Error("文件读取失败")); reader.readAsDataURL(file); }); } /** * 设置新图像的属性 * @private */ _setupNewImageProperties() { if (!this.newImageObject || !this.originalLayer) return; // 生成新的ID const newId = `fixed_image_${Date.now()}_${Math.floor( Math.random() * 1000 )}`; // 基本属性设置 this.newImageObject.set({ id: newId, layerId: this.originalLayer.id, layerName: this.originalLayer.name, selectable: false, // 固定图层通常不可选择 evented: false, // 固定图层通常不响应事件 visible: this.originalLayer.visible, opacity: this.originalLayer.opacity || 1.0, }); // 如果有原始对象,继承其位置和变换属性 if (this.originalObject) { this.newImageObject.set({ left: this.originalObject.left, top: this.originalObject.top, scaleX: this.originalObject.scaleX, scaleY: this.originalObject.scaleY, angle: this.originalObject.angle, flipX: this.originalObject.flipX, flipY: this.originalObject.flipY, originX: this.originalObject.originX || "center", originY: this.originalObject.originY || "center", }); } else { // 如果没有原始对象,设置默认居中位置 const canvasCenter = this.canvas.getCenter(); this.newImageObject.set({ left: canvasCenter.left, top: canvasCenter.top, originX: "center", originY: "center", }); } // 如果是背景图层,可能需要特殊处理 if (this.originalLayer.isBackground) { this.newImageObject.set({ isBackground: true, }); } } /** * 替换图层中的对象 * @private */ _replaceLayerObject() { // 从画布移除原始对象 if ( this.originalObject && this.canvas.getObjects().includes(this.originalObject) ) { this.canvas.remove(this.originalObject); } // 添加新对象到画布 this.canvas.add(this.newImageObject); // 更新图层引用 this.originalLayer.fabricObject = this.newImageObject; // 如果图层有 fabricObjects 数组,也要更新 if (this.originalLayer.fabricObjects) { if (this.originalObject) { const index = this.originalLayer.fabricObjects.indexOf( this.originalObject ); if (index !== -1) { this.originalLayer.fabricObjects[index] = this.newImageObject; } else { this.originalLayer.fabricObjects.push(this.newImageObject); } } else { this.originalLayer.fabricObjects.push(this.newImageObject); } } // 确保图层顺序正确(固定图层通常在特定位置) this._adjustObjectZIndex(); } /** * 调整对象的Z轴顺序 * @private */ _adjustObjectZIndex() { if (!this.newImageObject || !this.originalLayer) return; // 如果是背景图层,确保在最底层 if (this.originalLayer.isBackground) { this.newImageObject.sendToBack(); } else if (this.originalLayer.isFixed) { // 如果是固定图层,放在背景层之上,普通图层之下 const backgroundObjects = this.canvas .getObjects() .filter((obj) => obj.isBackground); if (backgroundObjects.length > 0) { this.newImageObject.bringForward(); // 向前移动一层 } } } async undo() { if (!this.canvas || !this.originalLayer) { console.error("无法撤销:缺少必要的状态信息"); return false; } try { // 从画布移除新对象 if ( this.newImageObject && this.canvas.getObjects().includes(this.newImageObject) ) { this.canvas.remove(this.newImageObject); } // 恢复原始对象 if (this.originalObject) { this.canvas.add(this.originalObject); this.originalLayer.fabricObject = this.originalObject; // 恢复 fabricObjects 数组 if (this.originalLayer.fabricObjects) { const newIndex = this.originalLayer.fabricObjects.indexOf( this.newImageObject ); if (newIndex !== -1) { this.originalLayer.fabricObjects[newIndex] = this.originalObject; } } } else { // 如果原来没有对象,清空图层引用 this.originalLayer.fabricObject = null; if (this.originalLayer.fabricObjects) { this.originalLayer.fabricObjects = this.originalLayer.fabricObjects.filter( (obj) => obj !== this.newImageObject ); } } // 重新渲染画布 this.canvas.renderAll(); console.log( `↩️ 成功撤销固定图层 "${this.originalLayer.name}" 的图像更改` ); return true; } catch (error) { console.error("撤销更改固定图层图像时发生错误:", error); return false; } } getInfo() { return { name: this.name, layerId: this.layerId, layerName: this.originalLayer?.name || "未知图层", fileName: this.newImageFile?.name || "未知文件", hasOriginalObject: !!this.originalObject, newImageId: this.newImageObject?.id, }; } } /** * 添加图像到图层命令 * 如果指定图层ID则添加到指定图层,否则创建新图层 */ export class AddImageToLayerCommand extends Command { constructor(options) { super({ name: "添加图像到图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.activeLayerId = options.activeLayerId; this.imageFile = options.imageFile; this.targetLayerId = options.targetLayerId; // 可选:指定目标图层ID this.layerManager = options.layerManager; this.toolManager = options.toolManager; // 执行结果 this.createdImageObject = null; this.usedLayerId = null; this.wasLayerCreated = false; this.subCommands = []; this.executedSubCommands = []; } async execute() { if (!this.canvas || !this.layers || !this.imageFile) { throw new Error("添加图像到图层命令缺少必要参数"); } try { // 创建图像对象 this.createdImageObject = await this._createImageFromFile(this.imageFile); // 确定目标图层 const targetLayer = await this._determineTargetLayer(); this.usedLayerId = targetLayer.id; // 添加图像到图层 await this._addImageToLayer(targetLayer); // 切换到选择工具 await this._switchToSelectTool(); console.log(`✅ 成功添加图像到图层 "${targetLayer.name}"`); return { layerId: this.usedLayerId, imageId: this.createdImageObject.id, wasLayerCreated: this.wasLayerCreated, }; } catch (error) { console.error("添加图像到图层失败:", error); // 回滚已执行的子命令 await this._rollbackSubCommands(); throw error; } } /** * 从文件创建图像对象 * @param {File} file 图像文件 * @returns {Promise} 图像对象 * @private */ async _createImageFromFile(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { fabric.Image.fromURL( e.target.result, (img) => { if (!img) { reject(new Error("无法创建图像对象")); return; } // 设置图像基本属性 const imageId = `image_${Date.now()}_${Math.floor( Math.random() * 1000 )}`; // 获取画布中心点 const canvasCenter = this.canvas.getCenter(); img.set({ id: imageId, left: canvasCenter.left, top: canvasCenter.top, originX: "center", originY: "center", selectable: true, evented: true, }); resolve(img); }, { crossOrigin: "anonymous", } ); }; reader.onerror = () => reject(new Error("文件读取失败")); reader.readAsDataURL(file); }); } /** * 确定目标图层 * @returns {Promise} 目标图层对象 * @private */ async _determineTargetLayer() { // 如果指定了目标图层ID,查找该图层 if (this.targetLayerId) { const existingLayer = this.layers.value.find( (layer) => layer.id === this.targetLayerId ); if (existingLayer) { // 验证图层是否可以添加对象 if (existingLayer.isBackground) { throw new Error("不能向背景图层添加对象"); } if (existingLayer.locked) { throw new Error("不能向锁定图层添加对象"); } console.log(`使用指定图层: ${existingLayer.name}`); return existingLayer; } else { console.warn(`指定的图层ID不存在: ${this.targetLayerId},将创建新图层`); } } // 创建新图层 return await this._createNewLayer(); } /** * 创建新图层 * @returns {Promise} 新创建的图层对象 * @private */ async _createNewLayer() { // 生成图层名称 const fileName = this.imageFile.name.replace(/\.[^/.]+$/, ""); // 移除文件扩展名 const layerName = fileName || `图片 ${new Date().toLocaleTimeString()}`; // 创建图层对象 const newLayer = createLayer({ name: layerName, type: LayerType.BITMAP, visible: true, locked: false, opacity: 1.0, fabricObjects: [], }); // 执行添加图层命令 const addLayerCmd = new AddLayerCommand({ canvas: this.canvas, layers: this.layers, newLayer: newLayer, activeLayerId: this.activeLayerId, insertIndex: this.layerManager?._getInsertIndexAboveActiveLayer?.(), }); const layerId = await addLayerCmd.execute(); this.subCommands.push(addLayerCmd); this.executedSubCommands.push(addLayerCmd); this.wasLayerCreated = true; console.log(`创建新图层: ${layerName}, ID: ${layerId}`); return newLayer; } /** * 添加图像到图层 * @param {Object} targetLayer 目标图层 * @private */ async _addImageToLayer(targetLayer) { // 设置图像与图层的关联 this.createdImageObject.set({ layerId: targetLayer.id, layerName: targetLayer.name, }); // 执行添加对象到图层命令 const addObjectCmd = new AddObjectToLayerCommand({ canvas: this.canvas, layers: this.layers, layerId: targetLayer.id, fabricObject: this.createdImageObject, }); await addObjectCmd.execute(); this.subCommands.push(addObjectCmd); this.executedSubCommands.push(addObjectCmd); console.log(`图像已添加到图层: ${targetLayer.name}`); } /** * 切换到选择工具 * @private */ async _switchToSelectTool() { if (!this.toolManager) return; const toolCmd = new ToolCommand({ toolManager: this.toolManager, tool: OperationType.SELECT, previousTool: this.toolManager.getCurrentTool(), }); await toolCmd.execute(); this.subCommands.push(toolCmd); this.executedSubCommands.push(toolCmd); console.log("已切换到选择工具"); } /** * 回滚已执行的子命令 * @private */ async _rollbackSubCommands() { console.log(`🔄 开始回滚 ${this.executedSubCommands.length} 个子命令`); const commands = [...this.executedSubCommands].reverse(); for (const command of commands) { if (typeof command.undo === "function") { try { console.log(`🔄 回滚子命令: ${command.constructor.name}`); const result = command.undo(); if (this._isPromise(result)) { await result; } console.log(`✅ 子命令回滚成功: ${command.constructor.name}`); } catch (error) { console.error( `❌ 子命令回滚失败: ${command.constructor.name}`, error ); } } } this.executedSubCommands = []; console.log(`✅ 回滚完成`); } async undo() { if (this.executedCommands.length === 0) { console.warn("没有已执行的命令需要撤销"); return true; } console.log( `↩️ 开始撤销创建图片图层操作,共 ${this.executedCommands.length} 个子命令` ); try { // 逆序撤销已执行的命令 const commands = [...this.executedCommands].reverse(); for (const command of commands) { if (typeof command.undo === "function") { try { console.log(`↩️ 撤销子命令: ${command.constructor.name}`); const result = command.undo(); if (this._isPromise(result)) { await result; } console.log(`✅ 子命令撤销成功: ${command.constructor.name}`); } catch (error) { console.error( `❌ 子命令撤销失败: ${command.constructor.name}`, error ); } } } this.executedCommands = []; console.log(`✅ 创建图片图层撤销完成`); return true; } catch (error) { console.error("❌ 撤销创建图片图层过程中发生错误:", error); throw error; } } /** * 检查返回值是否为Promise * @private */ _isPromise(value) { return ( value && typeof value === "object" && typeof value.then === "function" && typeof value.catch === "function" ); } getInfo() { return { name: this.name, layerName: this.layerName, layerId: this.newLayerId, commandCount: this.commands.length, executedCount: this.executedCommands.length, }; } }