import { Command } from "./Command"; import { fabric } from "fabric-with-all"; import { LayerType, OperationType, createLayer, findLayerRecursively, } from "../utils/layerHelper"; import { generateId, optimizeCanvasRendering, findObjectById, removeCanvasObjectByObject, } from "../utils/helper"; import { createRasterizedImage } from "../utils/rasterizedImage"; import { message } from "ant-design-vue"; import { restoreFabricObject } from "../utils/objectHelper"; /** * 组合图层命令 * 将图层中的所有矢量对象转换为位图图像 * 支持普通图层和组图层的组合 */ export class RasterizeLayerCommand extends Command { constructor(options) { super({ name: "组合图层", saveState: true, }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; // 指定要组合的图层ID // 是否包含锁定对象 this.hasLocked = options.hasLocked || true; // 是否包含隐藏对象 this.hasHidden = options.hasHidden || false; this.activeLayerId = options.activeLayerId; this.layerManager = options.layerManager; // 查找目标图层 const { layer, parent } = findLayerRecursively( this.layers.value, this.layerId ); this.layer = layer; this.parentLayer = parent; // 新增:如果有父图层,则栅格化父图层及其所有子图层 if (this.parentLayer) { this.layer = this.parentLayer; this.layerId = this.parentLayer.id; } this.isGroupLayer = this.layer?.children && this.layer.children.length > 0; if (!this.layer) { throw new Error(`图层 ${this.layerId} 不存在`); } // 检查是否可以组合 if (this.layer.isBackground || this.layer.isFixed) { throw new Error("背景图层和固定图层不能组合"); } // 生成新图层ID this.rasterizedLayerId = generateId("rasterized_layer_"); this.resterizedId = generateId("rasterized_"); this.rasterizedLayer = null; // 要组合的图层和对象 this.layersToRasterize = []; this.objectsToRasterize = []; // 在构造函数中收集相关对象和保存状态 this._initializeCommand(); } async execute() { if (!this.layer) { throw new Error(`图层 ${this.layerId} 不存在`); } if (this.objectsToRasterize.length === 0) { throw new Error("图层没有内容可组合"); } try { this.canvas.discardActiveObject(); this.canvas.renderAll(); // 检查是否有遮罩对象 const maskObject = await this._getMaskObject(); // 创建组合图像 const rasterizedImage = await createRasterizedImage({ canvas: this.canvas, fabricObjects: this.objectsToRasterize, maskObject: maskObject, preserveOriginalQuality: true, // 保持原始质量 isGroupWithMask: this.isGroupLayer && !!maskObject, // 标记是否为带遮罩的组 }); // 创建新的组合图层并替换原图层 await this._createRasterizedLayer(rasterizedImage); // 切换到选择工具 this.layerManager?.toolManager?.setTool?.(OperationType.SELECT); console.log(`✅ 图层 ${this.layer.name} 组合完成`); this.canvas?.thumbnailManager?.generateLayerThumbnail?.( this.rasterizedLayerId ); this.layerManager.activeLayerId.value = this.rasterizedLayerId; return this.rasterizedLayerId; } catch (error) { console.error("组合图层失败:", error); throw error; } } async undo() { if (!this.originalObjectStates || this.originalObjectStates.size === 0) { throw new Error("没有可恢复的原始数据"); } try { await optimizeCanvasRendering(this.canvas, async () => { // 移除组合后的图像对象 if (this.rasterizedImage) { removeCanvasObjectByObject(this.canvas, this.rasterizedImage); } // 恢复原始对象 this.originalObjectStates.forEach((originalState, objectId) => { const { object } = findObjectById(this.canvas, objectId); if (object) { // 恢复对象状态 object.set(originalState); object.setCoords(); } else { // 如果对象不在画布上,重新添加 const originalObject = originalState._fabricObject; if (originalObject) { this.canvas.add(originalObject); originalObject.setCoords(); } } }); // 恢复原始图层结构 this.layers.value = [...this.originalLayerStructure]; // 恢复原活动图层 this.activeLayerId.value = this.layerId; // 更新画布交互性 await this.layerManager?.updateLayersObjectsInteractivity(false); }); console.log(`↩️ 图层 ${this.layer.name} 组合已撤销`); return true; } catch (error) { console.error("撤销组合失败:", error); throw error; } } /** * 初始化命令,收集相关图层和对象,保存原始状态 * @private */ _initializeCommand() { // 收集要组合的图层和对象 this._collectLayersAndObjects(); // 保存原始图层结构(深拷贝相关部分) this._saveOriginalLayerStructure(); // 保存原始对象状态 this._saveOriginalObjectStates(); } /** * 保存原始图层结构 * @private */ _saveOriginalLayerStructure() { // 只保存相关的图层结构,而不是整个图层数组 this.originalLayerStructure = JSON.parse(JSON.stringify(this.layers.value)); } /** * 保存原始对象状态 * @private */ _saveOriginalObjectStates() { this.originalObjectStates = new Map(); this.objectsToRasterize.forEach((object) => { if (object && object.id) { // 深拷贝对象的重要属性 const originalState = { left: object.left, top: object.top, scaleX: object.scaleX, scaleY: object.scaleY, angle: object.angle, flipX: object.flipX, flipY: object.flipY, opacity: object.opacity, originX: object.originX, originY: object.originY, layerId: object.layerId, layerName: object.layerName, width: object.width, height: object.height, strokeWidth: object.strokeWidth, visible: object.visible, // 保存对象引用以便撤销时重新添加 _fabricObject: object, }; this.originalObjectStates.set(object.id, originalState); } }); console.log(`💾 保存了 ${this.originalObjectStates.size} 个对象的原始状态`); } /** * 收集要组合的图层和对象 * @private */ _collectLayersAndObjects() { if (this.isGroupLayer) { // 组图层:收集自身和所有子图层 this.layersToRasterize = this._collectLayersToRasterize(this.layer); } else { // 普通图层:只收集自身 this.layersToRasterize = [this.layer]; } // 收集所有图层的fabricObjects并按画布z-index顺序排序 const allCanvasObjects = this.canvas.getObjects(); const objectsWithZIndex = []; this.layersToRasterize.forEach((layer) => { // if (layer.fill) { // const { object } = findObjectById(this.canvas, layer.fill.id); // if (object) { // // 获取对象在画布中的z-index(数组索引) // const zIndex = allCanvasObjects.indexOf(object); // objectsWithZIndex.push({ // object: object, // zIndex: zIndex, // layerObj: layer.fill, // }); // } // } if (layer.fabricObjects && layer.fabricObjects.length > 0) { layer.fabricObjects.forEach((layerObj) => { if (layerObj && layerObj.id) { const { object } = findObjectById(this.canvas, layerObj.id); if (object) { // 获取对象在画布中的z-index(数组索引) const zIndex = allCanvasObjects.indexOf(object); objectsWithZIndex.push({ object: object, zIndex: zIndex, layerObj: layerObj, }); } } }); } }); // 按z-index排序,确保保持原有的渲染顺序 objectsWithZIndex.sort((a, b) => a.zIndex - b.zIndex); // 提取排序后的对象 this.objectsToRasterize = objectsWithZIndex.map((item) => item.object); console.log( `📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合` ); console.log( "🔢 对象z-index顺序:", objectsWithZIndex.map((item) => ({ id: item.object.id, type: item.object.type, zIndex: item.zIndex, })) ); } /** * 收集要组合的图层(递归收集子图层) * @param {Object} sourceLayer 源图层 * @returns {Array} 图层数组 * @private */ _collectLayersToRasterize(sourceLayer) { const result = [sourceLayer]; // 如果是组图层,收集所有子图层 if (sourceLayer.children && sourceLayer.children.length > 0) { sourceLayer.children.forEach((childLayer) => { if (childLayer) { result.push(...this._collectLayersToRasterize(childLayer)); } }); } return result; } /** * 创建组合图层并替换原图层 * @param {fabric.Image} rasterizedImage 组合后的图像 * @private */ async _createRasterizedLayer(rasterizedImage) { // 保存组合图像的引用用于撤销 this.rasterizedImage = rasterizedImage; // 从画布中移除原有对象 this.objectsToRasterize.forEach((obj) => { removeCanvasObjectByObject(this.canvas, obj); }); // 添加组合图像到画布 this.canvas.add(rasterizedImage); this.canvas.setActiveObject(rasterizedImage); // 创建新的组合图层 this.rasterizedLayer = createLayer({ id: this.rasterizedLayerId, name: `${this.layer.name} (组合)`, type: LayerType.BITMAP, visible: this.layer.visible, locked: this.layer.locked, opacity: this.layer.opacity, fabricObjects: [rasterizedImage], }); // 更新图像对象的图层关联 rasterizedImage.set({ id: this.resterizedId, // type: "image", layerId: this.rasterizedLayerId, layerName: this.rasterizedLayer.name, }); // 在适当位置添加新的组合图层 this._replaceLayerInStructure(); // 设置为活动图层 this.activeLayerId.value = this.rasterizedLayerId; await this.layerManager?.updateLayersObjectsInteractivity(false); console.log(`🎨 组合图层 ${this.rasterizedLayer.name} 创建完成`); } /** * 在图层结构中替换原图层 * @private */ _replaceLayerInStructure() { // 1.当前如果是子图层,则插入到子图层的位置 const { layer, parent } = findLayerRecursively( this.layers.value, this.layerId ); let insertIndex = 0; // 说明是子图层 if (parent) { this.layers.value.some((l, index) => { if (l.id === parent.id) { insertIndex = this.layers.value?.[index].children?.findIndex( (fItem) => fItem.id === this.layerId ); return true; // 找到父图层,停止循环 } return false; // 继续查找 }); } else { insertIndex = this.layers.value.findIndex((l) => l.id === this.layerId); } if (insertIndex !== -1) { if (parent) { const pIndex = this.layers.value.findIndex((l) => l.id === parent.id); this.layers.value[pIndex].children?.splice?.( insertIndex, 1, this.rasterizedLayer ); } else { this.layers.value.splice(insertIndex, 1, this.rasterizedLayer); } } else { // 2.如果没有找到父图层,则添加到顶层 this.layers.value.unshift(this.rasterizedLayer); } } /** * 获取遮罩对象 * @returns {Object|null} 遮罩对象或null * @private */ async _getMaskObject() { // 如果图层有clippingMask,获取对应的fabric对象 if (this.layer?.clippingMask) { const { object: maskObject } = findObjectById( this.canvas, this.layer.clippingMask.id ); if (maskObject) { console.log( `📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}` ); return maskObject; } return await restoreFabricObject(this.layer.clippingMask); } console.log("📎 未找到遮罩对象"); return null; } getInfo() { return { name: this.name, originalLayerId: this.layerId, originalLayerName: this.layer?.name, rasterizedLayerId: this.rasterizedLayerId, rasterizedLayerName: this.rasterizedLayer?.name, isGroupLayer: this.isGroupLayer, objectCount: this.objectsToRasterize?.length || 0, }; } } /** * 导出图层命令 * 将图层中的所有矢量对象转换为位图图像 * 支持普通图层和组图层的组合 */ export class ExportLayerToImageCommand extends Command { constructor(options) { super({ name: "导出图层", saveState: false, // 导出不需要保存状态 }); this.canvas = options.canvas; this.layers = options.layers; this.layerId = options.layerId; // 指定要导出的图层ID // 是否包含锁定对象 this.hasLocked = options.hasLocked || true; // 是否包含隐藏对象 this.hasHidden = options.hasHidden || false; this.activeLayerId = options.activeLayerId; this.layerManager = options.layerManager; // 查找目标图层 const { layer, parent } = findLayerRecursively( this.layers.value, this.layerId ); this.layer = layer; this.parentLayer = parent; this.isGroupLayer = this.layer?.children && this.layer.children.length > 0; if (!this.layer) { throw new Error(`图层 ${this.layerId} 不存在`); } // 要导出的图层和对象 this.layersToRasterize = []; this.objectsToRasterize = []; // 收集相关对象 this._collectLayersAndObjects(); } async execute() { if (!this.layer) { throw new Error(`图层 ${this.layerId} 不存在`); } if (this.objectsToRasterize.length === 0) { message.error("图层没有内容可导出"); throw new Error("图层没有内容可导出"); } try { // 保存原始对象状态 this.canvas.discardActiveObject(); this.canvas.renderAll(); // 重新创建遮罩对象 let clippingMaskFabricObject = null; if (this.layer?.clippingMask) { // 重新创建遮罩对象 clippingMaskFabricObject = await restoreFabricObject( this.layer?.clippingMask, this.canvas ); clippingMaskFabricObject.clipPath = null; clippingMaskFabricObject.set({ absolutePositioned: true, }); clippingMaskFabricObject.dirty = true; clippingMaskFabricObject.setCoords(); } // 创建图像 const imageBase64 = await createRasterizedImage({ canvas: this.canvas, fabricObjects: this.objectsToRasterize, isReturenDataURL: true, maskObject: clippingMaskFabricObject || null, // 不处理遮罩 }); // 模拟浏览器下载 const link = document.createElement("a"); link.href = imageBase64; link.download = `${this.layer.name}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); console.log(`✅ 图层 ${this.layer.name} 导出完成`); return true; } catch (error) { console.error("导出图层失败:", error); throw error; } } async undo() { // 导出图片不需要撤销操作 } /** * 收集要组合的图层和对象 * @private */ _collectLayersAndObjects() { if (this.isGroupLayer) { // 组图层:收集自身和所有子图层 this.layersToRasterize = this._collectLayersToRasterize(this.layer); } else { // 普通图层:只收集自身 this.layersToRasterize = [this.layer]; } // 收集所有图层的fabricObjects并按画布z-index顺序排序 const allCanvasObjects = this.canvas.getObjects(); const objectsWithZIndex = []; this.layersToRasterize.forEach((layer) => { // if (layer.fill) { // const { object } = findObjectById(this.canvas, layer.fill.id); // if (object) { // // 获取对象在画布中的z-index(数组索引) // const zIndex = allCanvasObjects.indexOf(object); // objectsWithZIndex.push({ // object: object, // zIndex: zIndex, // layerObj: layer.fill, // }); // } // } if (layer.fabricObjects && layer.fabricObjects.length > 0) { layer.fabricObjects.forEach((layerObj) => { if (layerObj && layerObj.id) { const { object } = findObjectById(this.canvas, layerObj.id); if (object) { // 获取对象在画布中的z-index(数组索引) const zIndex = allCanvasObjects.indexOf(object); objectsWithZIndex.push({ object: object, zIndex: zIndex, layerObj: layerObj, }); } } }); } }); // 按z-index排序,确保保持原有的渲染顺序 objectsWithZIndex.sort((a, b) => a.zIndex - b.zIndex); // 提取排序后的对象 this.objectsToRasterize = objectsWithZIndex.map((item) => item.object); console.log( `📊 收集到 ${this.layersToRasterize.length} 个图层,${this.objectsToRasterize.length} 个对象进行组合` ); console.log( "🔢 对象z-index顺序:", objectsWithZIndex.map((item) => ({ id: item.object.id, type: item.object.type, zIndex: item.zIndex, })) ); } /** * 收集要组合的图层(递归收集子图层) * @param {Object} sourceLayer 源图层 * @returns {Array} 图层数组 * @private */ _collectLayersToRasterize(sourceLayer) { const result = [sourceLayer]; // 如果是组图层,收集所有子图层 if (sourceLayer.children && sourceLayer.children.length > 0) { sourceLayer.children.forEach((childLayer) => { if (childLayer) { result.push(...this._collectLayersToRasterize(childLayer)); } }); } return result; } getInfo() { return { name: this.name, originalLayerId: this.layerId, originalLayerName: this.layer?.name, isGroupLayer: this.isGroupLayer, objectCount: this.objectsToRasterize?.length || 0, }; } }