feat: 裁剪组裁剪跟随选择组移动

This commit is contained in:
bighuixiang
2025-07-14 01:00:23 +08:00
parent 96e13cb22a
commit 24e9ba8ae5
80 changed files with 2052 additions and 4292 deletions

View File

@@ -1,8 +1,4 @@
import {
createLayer,
findInChildLayers,
LayerType,
} from "../utils/layerHelper.js";
import { createLayer, findInChildLayers, LayerType } from "../utils/layerHelper.js";
import { createRasterizedImage } from "../utils/selectionToImage.js";
import { CompositeCommand, Command } from "./Command.js";
import { CreateImageLayerCommand } from "./LayerCommands.js";
@@ -59,9 +55,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
const selectionObject = this.selectionManager.getSelectionObject();
if (selectionObject) {
try {
this._clonedSelectionObject = await this._cloneObject(
selectionObject
);
this._clonedSelectionObject = await this._cloneObject(selectionObject);
console.log("剪切选区:选区对象已克隆保存");
} catch (error) {
console.error("剪切选区:克隆选区对象失败:", error);
@@ -132,11 +126,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
}
// 步骤2: 对原图层进行栅格化处理,移除选区内容
await this._rasterizeOriginalLayerWithCutout(
sourceLayer,
sourceObjects,
selectionObject
);
await this._rasterizeOriginalLayerWithCutout(sourceLayer, sourceObjects, selectionObject);
// 步骤3: 创建图像图层命令
const createImageLayerCmd = new CreateImageLayerCommand({
@@ -246,10 +236,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
console.log(`✅ 子命令撤销成功: ${command.constructor.name}`);
}
} catch (error) {
console.error(
`❌ 子命令撤销失败: ${command.constructor.name}`,
error
);
console.error(`❌ 子命令撤销失败: ${command.constructor.name}`, error);
// 子命令撤销失败不中断整个撤销过程
}
}
@@ -313,17 +300,14 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
await this._restoreObjectsFromBackup(sourceLayer);
} else {
// 备用方案恢复原始的fabricObjects数组
sourceLayer.fabricObjects =
this.originalLayerBackup.fabricObjects || [];
sourceLayer.fabricObjects = this.originalLayerBackup.fabricObjects || [];
if (sourceLayer.fabricObjects.length > 0) {
await this._restoreLayerObjects(sourceLayer);
}
}
console.log(
`✅ 原图层状态恢复完成,恢复了 ${sourceLayer.fabricObjects.length} 个对象`
);
console.log(`✅ 原图层状态恢复完成,恢复了 ${sourceLayer.fabricObjects.length} 个对象`);
} catch (error) {
console.error("恢复原图层状态失败:", error);
throw error;
@@ -337,78 +321,68 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
*/
async _restoreObjectsFromBackup(layer) {
return new Promise((resolve, reject) => {
if (
!this.originalLayerObjectsData ||
this.originalLayerObjectsData.length === 0
) {
if (!this.originalLayerObjectsData || this.originalLayerObjectsData.length === 0) {
console.warn("没有对象备份数据");
resolve();
return;
}
try {
console.log(
`开始从备份恢复 ${this.originalLayerObjectsData.length} 个对象...`
);
console.log(`开始从备份恢复 ${this.originalLayerObjectsData.length} 个对象...`);
// 使用fabric.util.enlivenObjects重建对象
fabric.util.enlivenObjects(
this.originalLayerObjectsData,
(restoredObjects) => {
try {
let successCount = 0;
fabric.util.enlivenObjects(this.originalLayerObjectsData, (restoredObjects) => {
try {
let successCount = 0;
restoredObjects.forEach((obj, index) => {
if (obj) {
// 确保对象有正确的属性
obj.set({
layerId: layer.id,
layerName: layer.name,
selectable: true,
evented: true,
visible: true,
});
restoredObjects.forEach((obj, index) => {
if (obj) {
// 确保对象有正确的属性
obj.set({
layerId: layer.id,
layerName: layer.name,
selectable: true,
evented: true,
visible: true,
});
// 添加到画布
this.canvas.add(obj);
// 添加到画布
this.canvas.add(obj);
// 添加到图层的fabricObjects数组
layer.fabricObjects.push(
obj.toObject([
"id",
"layerId",
"layerName",
"parentId",
"selectable",
"evented",
"visible",
])
);
// 添加到图层的fabricObjects数组
layer.fabricObjects.push(
obj.toObject([
"id",
"layerId",
"layerName",
"parentId",
"selectable",
"evented",
"visible",
])
);
successCount++;
console.log(
`恢复对象 ${index + 1}/${restoredObjects.length}: ${
obj.id || obj.type
}`
);
} else {
console.warn(`对象 ${index + 1} 恢复失败`);
}
});
successCount++;
console.log(
`恢复对象 ${index + 1}/${restoredObjects.length}: ${obj.id || obj.type}`
);
} else {
console.warn(`对象 ${index + 1} 恢复失败`);
}
});
// 重新渲染画布
this.canvas.renderAll();
// 重新渲染画布
this.canvas.renderAll();
console.log(
`✅ 成功恢复了 ${successCount}/${this.originalLayerObjectsData.length} 个对象`
);
resolve();
} catch (error) {
console.error("处理恢复的对象时出错:", error);
reject(error);
}
console.log(
`✅ 成功恢复了 ${successCount}/${this.originalLayerObjectsData.length} 个对象`
);
resolve();
} catch (error) {
console.error("处理恢复的对象时出错:", error);
reject(error);
}
);
});
} catch (error) {
console.error("恢复对象时出错:", error);
reject(error);
@@ -474,11 +448,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
* @returns {fabric.Image} 抠图结果的fabric图像对象
* @private
*/
async _performCutoutWithRasterized(
sourceObjects,
selectionObject,
selectionBounds
) {
async _performCutoutWithRasterized(sourceObjects, selectionObject, selectionBounds) {
try {
console.log("=== 开始使用createRasterizedImage执行剪切抠图 ===");
console.log(`源对象数量: ${sourceObjects.length}`);
@@ -488,10 +458,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
let scaleFactor = this.baseResolutionScale;
if (this.highResolutionEnabled) {
const currentZoom = this.canvas.getZoom?.() || 1;
scaleFactor = Math.max(
scaleFactor || this.canvas?.getRetinaScaling?.(),
currentZoom
);
scaleFactor = Math.max(scaleFactor || this.canvas?.getRetinaScaling?.(), currentZoom);
scaleFactor = Math.min(scaleFactor, 3);
}
@@ -535,15 +502,10 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
// 递归获取图层及其子图层的所有对象
const collectLayerObjects = (currentLayer) => {
// 处理图层的fabricObjects
if (
currentLayer.fabricObjects &&
Array.isArray(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
);
const realObject = canvasObjects.find((canvasObj) => canvasObj.id === fabricObj.id);
if (realObject && realObject.visible !== false) {
objects.push(realObject);
}
@@ -649,17 +611,14 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
}
});
} else if (objectType === "polygon") {
fabric.Polygon.fromObject(
this.serializedSelectionObject,
(polygon) => {
if (polygon) {
console.log("多边形选区对象反序列化成功");
resolve(polygon);
} else {
reject(new Error("多边形选区对象反序列化失败"));
}
fabric.Polygon.fromObject(this.serializedSelectionObject, (polygon) => {
if (polygon) {
console.log("多边形选区对象反序列化成功");
resolve(polygon);
} else {
reject(new Error("多边形选区对象反序列化失败"));
}
);
});
} else if (objectType === "rect") {
fabric.Rect.fromObject(this.serializedSelectionObject, (rect) => {
if (rect) {
@@ -670,30 +629,24 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
}
});
} else if (objectType === "ellipse" || objectType === "circle") {
fabric.Ellipse.fromObject(
this.serializedSelectionObject,
(ellipse) => {
if (ellipse) {
console.log("椭圆选区对象反序列化成功");
resolve(ellipse);
} else {
reject(new Error("椭圆选区对象反序列化失败"));
}
fabric.Ellipse.fromObject(this.serializedSelectionObject, (ellipse) => {
if (ellipse) {
console.log("椭圆选区对象反序列化成功");
resolve(ellipse);
} else {
reject(new Error("椭圆选区对象反序列化失败"));
}
);
});
} else {
// 通用对象反序列化
fabric.util.enlivenObjects(
[this.serializedSelectionObject],
(objects) => {
if (objects && objects.length > 0) {
console.log("通用选区对象反序列化成功");
resolve(objects[0]);
} else {
reject(new Error("通用选区对象反序列化失败"));
}
fabric.util.enlivenObjects([this.serializedSelectionObject], (objects) => {
if (objects && objects.length > 0) {
console.log("通用选区对象反序列化成功");
resolve(objects[0]);
} else {
reject(new Error("通用选区对象反序列化失败"));
}
);
});
}
});
} catch (error) {
@@ -761,9 +714,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
this.originalLayerRasterized = false; // 标记原图层是否已栅格化
console.log(
`✅ 原图层状态已备份,对象数量: ${this.originalLayerObjectsData.length}`
);
console.log(`✅ 原图层状态已备份,对象数量: ${this.originalLayerObjectsData.length}`);
} catch (error) {
console.error("备份原图层状态失败:", error);
throw error;
@@ -777,11 +728,7 @@ export class CutSelectionToNewLayerCommand extends CompositeCommand {
* @param {Object} selectionObject 选区对象
* @private
*/
async _rasterizeOriginalLayerWithCutout(
sourceLayer,
sourceObjects,
selectionObject
) {
async _rasterizeOriginalLayerWithCutout(sourceLayer, sourceObjects, selectionObject) {
try {
console.log("=== 开始对原图层进行栅格化处理,移除选区内容 ===");