feat: 优化选区功能,修复部分bug

This commit is contained in:
bighuixiang
2025-07-10 01:01:46 +08:00
parent 943b49c1d7
commit 7359fe2f9a
11 changed files with 1667 additions and 126 deletions

View File

@@ -14,7 +14,7 @@ import { generateId } from "../utils/helper.js";
/**
* 套索抠图命令
* 实现将选区内容抠图到新图层的功能
* 实现将选区内容到新图层遮罩
*/
export class LassoCutoutCommand extends CompositeCommand {
constructor(options = {}) {
@@ -36,8 +36,11 @@ export class LassoCutoutCommand extends CompositeCommand {
this.highResolutionEnabled = options.highResolutionEnabled !== false; // 默认启用
this.baseResolutionScale = options.baseResolutionScale || 2; // 基础分辨率倍数
this.groupId = options.groupId || `cutout-group-${Date.now()}`;
this.groupId = options.groupId || generateId("lasso-group-");
this.groupName = options.groupName || `选区组`;
this.clippingMaskId = generateId("clipping-mask-");
this.groupLayer = null; // 新增:保存组图层的引用
this.originalLayersLength = 0; // 新增:保存原始图层数量
@@ -51,6 +54,8 @@ export class LassoCutoutCommand extends CompositeCommand {
this.originalFabricObjects = []; // 保存原图层的所有fabric对象序列化
this.originalCanvasObjects = []; // 保存从画布中获取的真实fabric对象
this._initializeOriginalLayerInfo();
this.oldActiveLayerId = this.layerManager.activeLayerId.value; // 保存旧的活动图层ID
}
/**
@@ -144,14 +149,24 @@ export class LassoCutoutCommand extends CompositeCommand {
}
// 获取源图层的所有对象(包括子图层)
const sourceObjects = this._getLayerObjects(sourceLayer);
if (sourceObjects.length === 0) {
console.error("无法执行套索抠图:源图层没有可见对象");
return false;
}
// const sourceObjects = this._getLayerObjects(sourceLayer);
// if (sourceObjects.length === 0) {
// console.error("无法执行套索抠图:源图层没有可见对象");
// return false;
// }
const clippingMask = fabric.util.object.clone(selectionObject);
clippingMask.set({
id: this.clippingMaskId,
selectable: false,
evented: false,
hasControls: false,
// layerId: this.groupId,
visible: true,
});
// 获取选区边界信息用于后续定位
const selectionBounds = selectionObject.getBoundingRect(true, true);
// const selectionBounds = selectionObject.getBoundingRect(true, true);
// 使用createRasterizedImage执行抠图操作
// this.cutoutImageUrl = await this._performCutoutWithRasterized(
@@ -164,46 +179,34 @@ export class LassoCutoutCommand extends CompositeCommand {
// return false;
// }
this.fabricImage = await this._performCutoutWithRasterized(
sourceObjects,
selectionObject,
selectionBounds
);
// this.fabricImage = await this._performCutoutWithRasterized(
// sourceObjects,
// selectionObject,
// selectionBounds
// );
// // 创建fabric图像对象传递选区边界信息
// this.fabricImage = await this._createFabricImage(
// this.cutoutImageUrl,
// selectionBounds
// );
if (!this.fabricImage) {
console.error("创建图像对象失败");
return false;
}
// if (!this.fabricImage) {
// console.error("创建图像对象失败");
// return false;
// }
// 1. 创建图像图层命令
const createImageLayerCmd = new CreateImageLayerCommand({
layerManager: this.layerManager,
fabricImage: this.fabricImage,
toolManager: this.toolManager,
layerName: this.newLayerName,
});
// const createImageLayerCmd = new CreateImageLayerCommand({
// layerManager: this.layerManager,
// fabricImage: this.fabricImage,
// toolManager: this.toolManager,
// layerName: this.newLayerName,
// });
// 执行创建图像图层命令
const result = await createImageLayerCmd.execute();
this.newLayerId = createImageLayerCmd.newLayerId;
this.executedCommands.push(createImageLayerCmd);
// 2. 删除原图层命令
const removeOriginalLayerCmd = new RemoveLayerCommand({
canvas: this.canvas,
layers: this.layerManager.layers,
layerId: this.originalLayer.id,
activeLayerId: this.layerManager.activeLayerId,
});
// 执行删除原图层命令
await removeOriginalLayerCmd.execute();
this.executedCommands.push(removeOriginalLayerCmd);
// // 执行创建图像图层命令
// const result = await createImageLayerCmd.execute();
// this.newLayerId = createImageLayerCmd.newLayerId;
// this.executedCommands.push(createImageLayerCmd);
// 3. 清除选区命令
const clearSelectionCmd = new ClearSelectionCommand({
@@ -216,10 +219,10 @@ export class LassoCutoutCommand extends CompositeCommand {
this.executedCommands.push(clearSelectionCmd);
const topLayerIndex = this.layerManager.layers.value.findIndex(
(layer) => layer.id === this.newLayerId
(layer) => layer.id === this.originalLayer.id
);
const selectLayer = this.layerManager.layers.value[topLayerIndex];
// const selectLayer = this.layerManager.layers.value[topLayerIndex];
// 创建新的组图层
this.groupLayer = createLayer({
@@ -233,28 +236,47 @@ export class LassoCutoutCommand extends CompositeCommand {
children: [],
});
this.fabricImage.set({
selectable: true,
evented: true,
// this.fabricImage.set({
// selectable: true,
// evented: true,
// });
const selectLayer = createLayer({
name: `选区空图层`,
type: LayerType.EMPTY,
visible: true,
locked: false,
opacity: 1.0,
fabricObjects: [],
children: [],
});
selectLayer.parentId = this.groupId; // 设置新图层的parentId为组图层ID
selectLayer.fabricObjects = [
this.fabricImage.toObject("id", "layerId", "layerName", "parentId"),
];
this.groupLayer.clippingMask = this.fabricImage.toObject(
"id",
"layerId",
"layerName",
"parentId"
); // 设置组图层的fabricObject为遮罩图像
// selectLayer.fabricObjects = [
// this.fabricImage.toObject("id", "layerId", "layerName", "parentId"),
// ];
// 2. 删除原图层命令
const removeOriginalLayerCmd = new RemoveLayerCommand({
canvas: this.canvas,
layers: this.layerManager.layers,
layerId: this.originalLayer.id,
activeLayerId: this.layerManager.activeLayerId,
});
// 执行删除原图层命令
await removeOriginalLayerCmd.execute();
this.executedCommands.push(removeOriginalLayerCmd);
this.groupLayer.clippingMask = clippingMask.toObject(["id", "layerId"]); // 设置组图层的fabricObject为遮罩图像
this.groupLayer.children.push(selectLayer);
// 插入新组图层
this.layerManager.layers.value.splice(topLayerIndex, 1, this.groupLayer);
this.layerManager.layers.value.splice(topLayerIndex, 0, this.groupLayer);
this.layerManager.activeLayerId.value = selectLayer.id; // 设置新组图层为活动图层
this.canvas.discardActiveObject();
this.canvas.setActiveObject(this.fabricImage);
// this.canvas.setActiveObject(this.fabricImage);
await this.layerManager.updateLayersObjectsInteractivity(true);
console.log(`套索抠图完成新图层ID: ${this.newLayerId}`);
@@ -328,6 +350,8 @@ export class LassoCutoutCommand extends CompositeCommand {
}
}
this.layerManager.activeLayerId.value = this.oldActiveLayerId; // 恢复旧的活动图层ID
if (this.fabricImage) {
console.log(`↩️ 移除抠图图像: ${this.fabricImage.id}`);
// 从画布中移除抠图图像