import { fabric } from "fabric-with-all"; import { Command } from "./Command"; import { createRasterizedImage } from "../utils/selectionToImage"; import { deepClone, findObjectById, generateId } from "../utils/helper"; import { findLayerRecursively } from "../utils/layerHelper"; /** * 从选区中删除内容命令 * 使用栅格化方式清除选区内容,支持复杂选区形状 */ export class ClearSelectionContentCommand extends Command { constructor(options = {}) { super({ name: "清除选区内容", description: "使用栅格化方式删除选区中的内容", saveState: true, }); this.canvas = options.canvas; this.layers = options.layerManager?.layers; this.layerManager = options.layerManager; this.selectionManager = options.selectionManager; this.targetLayerId = options.layerManager.getActiveLayerId(); // 默认使用当前活动图层 this.removedObjects = []; this.oldLayer = [...this.layers.value]; // 获取原图层对象 const { layer } = findLayerRecursively(this.layers.value, this.targetLayerId) || {}; // 栅格化相关属性 this.originalLayerBackup = null; const { object: originalLayerObject } = findObjectById( this.canvas, layer.fabricObjects?.[0]?.id ); // this.originalLayerObject = fabric.util.object.clone(originalLayerObject); // 获取原图层对象 this.oldLayerObjects = originalLayerObject.toObject(["id", "layerId", "layerName"]); // 获取原图层的所有对象 this.rasterizedImage = null; this.targetLayer = findLayerRecursively(this.canvas, this.targetLayerId)?.layer; this.layerRasterized = false; // 高清设置 this.highResolutionEnabled = options.highResolutionEnabled !== false; this.baseResolutionScale = options.baseResolutionScale || 2; // 支持外部传入选区对象,优先使用外部传入的选区对象 if (options.selectionObject) { // 外部传入的选区对象,直接使用 this.selectionObject = options.selectionObject; console.log("清除选区内容:使用外部传入的选区对象"); } else { // 从选区管理器获取选区对象 const currentSelection = this.selectionManager?.getSelectionObject(); if (currentSelection) { this.selectionObject = fabric.util.object.clone(currentSelection); console.log("清除选区内容:从选区管理器获取选区对象"); } else { this.selectionObject = null; console.warn("清除选区内容:没有可用的选区对象"); } } } async execute() { if (!this.canvas || !this.layerManager) { console.error("无法清除选区内容:参数无效"); return false; } try { // 获取选区 if (!this.selectionObject) { console.error("无法清除选区内容:当前没有选区"); return false; } // 确定目标图层 const layerId = this.targetLayerId || this.layerManager.getActiveLayerId(); this.targetLayer = this.layerManager.getLayerById(layerId); if (!this.targetLayer) { console.error("无法清除选区内容:目标图层无效"); return false; } // 备份原图层状态 // this.originalLayerBackup = JSON.parse(JSON.stringify(this.targetLayer)); // 获取图层的所有对象 const layerObjects = this._getLayerObjects(this.targetLayer); if (layerObjects.length === 0) { console.warn("目标图层没有对象,无需清除"); return true; } // 创建反转选区(保留选区外的内容) const invertedSelection = await this._createInvertedSelection(this.selectionObject); if (!invertedSelection) { console.error("创建反转选区失败"); return false; } // 使用栅格化方式清除选区内容 await this._rasterizeLayerWithClearance(layerObjects, invertedSelection); // 清除选区 this.selectionManager?.clearSelection?.(); console.log("✅ 选区内容清除完成"); return { cleared: true, layerId: this.targetLayer.id }; } catch (error) { console.error("清除选区内容失败:", error); // 尝试恢复原状态 await this._restoreOriginalState(); throw error; } } async undo() { try { this.layers.value = this.oldLayer; // 恢复原图层对象 // 恢复原图层状态 // 移除栅格化后的图像 if (this.rasterizedImage && this.canvas.getObjects().includes(this.rasterizedImage)) { this.canvas.remove(this.rasterizedImage); } // 恢复图层的fabricObjects // 重新创建并添加对象到画布 if (this.targetLayer.fabricObjects.length > 0) { await new Promise((resolve) => { fabric.util.enlivenObjects([this.oldLayerObjects], (objects) => { objects.forEach((obj) => { // 确保对象有正确的ID和图层信息 obj.set({ layerId: this.targetLayer.id, layerName: this.targetLayer.name, selectable: true, evented: true, }); // 添加到画布 this.canvas.add(obj); this.targetLayer.fabricObjects = [ obj.toObject(["id", "layerId", "layerName", "type", "custom"]), ]; }); this.canvas.renderAll(); resolve(); }); }); } await this.layerManager?.updateLayersObjectsInteractivity?.(true); this.layerRasterized = false; this.rasterizedImage = null; console.log("✅ 清除选区内容撤销完成"); return true; } catch (error) { console.error("❌ 撤销清除选区内容失败:", error); return false; } } /** * 使用栅格化方式清除选区内容 * @param {Array} layerObjects 图层对象数组 * @param {Object} invertedSelection 反转选区 * @private */ async _rasterizeLayerWithClearance(layerObjects, invertedSelection) { try { console.log("🖼️ 开始栅格化图层并清除选区内容"); // 确定缩放因子 let scaleFactor = this.baseResolutionScale; if (this.highResolutionEnabled) { const currentZoom = this.canvas.getZoom?.() || 1; scaleFactor = Math.max(scaleFactor || this.canvas?.getRetinaScaling?.(), currentZoom); scaleFactor = Math.min(scaleFactor, 3); } // 使用createRasterizedImage生成栅格化图像,使用反转选区作为裁剪路径 this.rasterizedImage = await createRasterizedImage({ canvas: this.canvas, fabricObjects: layerObjects, clipPath: invertedSelection, // 使用反转选区,保留选区外的内容 trimWhitespace: false, // 保持原始尺寸 trimPadding: 0, quality: 1.0, format: "png", scaleFactor: scaleFactor, preserveOriginalQuality: true, selectionManager: this.selectionManager, }); if (!this.rasterizedImage) { throw new Error("栅格化图层失败"); } // 移除原图层的所有对象 for (const obj of layerObjects) { if (this.canvas.getObjects().includes(obj)) { this.canvas.remove(obj); } } // 设置栅格化图像的属性 this.rasterizedImage.set({ id: generateId("cleared_"), layerId: this.targetLayer.id, layerName: this.targetLayer.name, selectable: true, evented: true, }); // 添加栅格化图像到画布和图层 this.canvas.add(this.rasterizedImage); this.targetLayer.fabricObjects = [ this.rasterizedImage.toObject("id", "layerId", "layerName", "parentId"), ]; this.layerRasterized = true; this.canvas.renderAll(); console.log("✅ 图层栅格化清除完成"); } catch (error) { console.error("栅格化图层清除失败:", error); throw error; } } /** * 创建反转选区 * @param {Object} selectionObject 原选区对象 * @returns {Object} 反转选区对象 * @private */ async _createInvertedSelection(selectionObject) { try { // 获取目标图层的所有对象 const layerObjects = this._getLayerObjects(this.targetLayer); if (layerObjects.length === 0) { console.warn("目标图层没有对象,无法创建反选区"); return null; } // 计算图层对象的边界框 const layerBounds = this._calculateLayerBounds(layerObjects); if (!layerBounds) { console.warn("无法计算图层边界框"); return null; } console.log("📐 图层边界框:", layerBounds); console.log("🎯 选区路径:", selectionObject.path); // 创建反转选区路径,使用图层边界而不是画布边界 const pathString = `M ${layerBounds.left} ${layerBounds.top} L ${ layerBounds.left + layerBounds.width } ${layerBounds.top} L ${layerBounds.left + layerBounds.width} ${ layerBounds.top + layerBounds.height } L ${layerBounds.left} ${layerBounds.top + layerBounds.height} Z ${selectionObject.path}`; const invertedPath = new fabric.Path(pathString, { fillRule: "evenodd", selectable: false, evented: false, fill: "#ffffff", // 确保填充颜色 stroke: "", strokeWidth: 0, id: `inverted_selection_${Date.now()}`, name: "inverted_selection", }); console.log("✅ 反转选区创建完成,使用图层边界框"); return invertedPath; } catch (error) { console.error("创建反转选区失败:", error); return null; } } /** * 计算图层对象的边界框 * @param {Array} layerObjects 图层对象数组 * @returns {Object|null} 边界框 {left, top, width, height} * @private */ _calculateLayerBounds(layerObjects) { if (!layerObjects || layerObjects.length === 0) { return null; } let bounds = null; layerObjects.forEach((obj) => { // 获取对象的边界框(包含变换) const objBounds = obj.getBoundingRect(true, true); if (!bounds) { bounds = { ...objBounds }; } else { const right = Math.max(bounds.left + bounds.width, objBounds.left + objBounds.width); const bottom = Math.max(bounds.top + bounds.height, objBounds.top + objBounds.height); bounds.left = Math.min(bounds.left, objBounds.left); bounds.top = Math.min(bounds.top, objBounds.top); bounds.width = right - bounds.left; bounds.height = bottom - bounds.top; } }); // 添加一些边距以确保完整覆盖 if (bounds) { const padding = 2; bounds.left -= padding; bounds.top -= padding; bounds.width += padding * 2; bounds.height += padding * 2; } return bounds; } /** * 获取图层的所有对象 * @param {Object} layer 图层对象 * @returns {Array} fabric对象数组 * @private */ _getLayerObjects(layer) { const objects = []; const canvasObjects = this.canvas.getObjects(); // 递归获取图层及其子图层的所有对象 const collectLayerObjects = (currentLayer) => { // 处理图层的fabricObjects if (currentLayer.fabricObjects && Array.isArray(currentLayer.fabricObjects)) { currentLayer.fabricObjects.forEach((fabricObj) => { if (fabricObj && fabricObj.id) { const realObject = canvasObjects.find((canvasObj) => canvasObj.id === fabricObj.id); if (realObject && realObject.visible !== false) { objects.push(realObject); } } }); } // 处理单个fabricObject(背景图层等) if (currentLayer.fabricObject && currentLayer.fabricObject.id) { const realObject = canvasObjects.find( (canvasObj) => canvasObj.id === currentLayer.fabricObject.id ); if (realObject && realObject.visible !== false) { objects.push(realObject); } } // 递归处理子图层 if (currentLayer.children && Array.isArray(currentLayer.children)) { currentLayer.children.forEach((childLayer) => { collectLayerObjects(childLayer); }); } }; collectLayerObjects(layer); return objects; } /** * 恢复原图层状态 * @private */ async _restoreOriginalState() { try { if (!this.originalLayerBackup || !this.targetLayer) { console.warn("没有原图层备份数据或目标图层"); return; } // 移除栅格化后的图像 if (this.rasterizedImage && this.canvas.getObjects().includes(this.rasterizedImage)) { this.canvas.remove(this.rasterizedImage); } // 恢复图层的fabricObjects this.targetLayer.fabricObjects = this.originalLayerBackup.fabricObjects || []; // 重新创建并添加对象到画布 if (this.targetLayer.fabricObjects.length > 0) { await this._restoreLayerObjects(this.targetLayer); } this.layerRasterized = false; this.rasterizedImage = null; console.log("✅ 原图层状态恢复完成"); } catch (error) { console.error("恢复原图层状态失败:", error); } } /** * 恢复图层对象到画布 * @param {Object} layer 图层对象 * @private */ async _restoreLayerObjects(layer) { return new Promise((resolve) => { if (!layer.fabricObjects || layer.fabricObjects.length === 0) { resolve(); return; } fabric.util.enlivenObjects(layer.fabricObjects, (objects) => { objects.forEach((obj) => { // 确保对象有正确的ID和图层信息 obj.set({ layerId: layer.id, layerName: layer.name, selectable: true, evented: true, }); // 添加到画布 this.canvas.add(obj); }); this.canvas.renderAll(); resolve(); }); }); } _cloneObjectSync(obj) { // 这是一个简单的深拷贝,不适用于所有场景 // 在实际应用中,应该使用fabric.js的clone方法 if (!obj) return null; return JSON.parse(JSON.stringify(obj)); } async _cloneObject(obj) { return new Promise((resolve, reject) => { if (!obj) { reject(new Error("对象无效,无法克隆")); return; } try { if (typeof obj.clone === "function") { obj.clone((cloned) => { resolve(cloned); }); } else { // 如果对象没有clone方法(可能是因为它已经是序列化后的对象) // 在实际代码中需要适当处理这种情况 resolve(Object.assign({}, obj)); } } catch (error) { reject(error); } }); } /** * 获取命令信息 * @returns {Object} 命令详细信息 */ getInfo() { return { name: this.name, description: this.description, targetLayerId: this.targetLayer?.id, targetLayerName: this.targetLayer?.name, layerRasterized: this.layerRasterized, hasOriginalBackup: !!this.originalLayerBackup, removedObjectsCount: this.removedObjects.length, highResolutionEnabled: this.highResolutionEnabled, baseResolutionScale: this.baseResolutionScale, }; } }