fix: 优化细节

This commit is contained in:
bighuixiang
2025-07-24 21:37:21 +08:00
parent 46b1c5cd71
commit 3ff5e27db6
10 changed files with 335 additions and 102 deletions

View File

@@ -72,7 +72,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
originY: clippingMaskFabricObject.originY || "center",
scaleX: clippingMaskFabricObject.scaleX || 1,
scaleY: clippingMaskFabricObject.scaleY || 1,
// type: "fill",
});
// this.newFill.clipPath = clippingMaskFabricObject;
// this.newFill.dirty = true;
@@ -92,7 +91,6 @@ export class FillGroupLayerBackgroundCommand extends Command {
evented: false,
originX: "center",
originY: "center",
// type: "fill",
});
}
}

View File

@@ -52,7 +52,10 @@ export class FillLayerBackgroundCommand extends Command {
let clippingMaskFabricObject = null;
if (layer.clippingMask) {
// 反序列化 clippingMask
clippingMaskFabricObject = await restoreFabricObject(layer.clippingMask, this.canvas);
clippingMaskFabricObject = await restoreFabricObject(
layer.clippingMask,
this.canvas
);
clippingMaskFabricObject.clipPath = null;
clippingMaskFabricObject.set({
@@ -75,7 +78,6 @@ export class FillLayerBackgroundCommand extends Command {
originY: clippingMaskFabricObject.originY || "center",
scaleX: clippingMaskFabricObject.scaleX || 1,
scaleY: clippingMaskFabricObject.scaleY || 1,
type: "fill",
});
this.newFill.clipPath = clippingMaskFabricObject; // 设置填充的遮罩
@@ -96,7 +98,6 @@ export class FillLayerBackgroundCommand extends Command {
evented: false,
originX: "center",
originY: "center",
type: "fill",
});
}
}
@@ -104,11 +105,15 @@ export class FillLayerBackgroundCommand extends Command {
// 判断fabricObjects是否是组是组则添加填充到最前面否则创建组
if (layer.fabricObjects && layer.fabricObjects.length > 0) {
let insertIndex =
this.canvas.getObjects()?.findIndex((obj) => obj.id === layer.fabricObjects?.[0]?.id) || 0;
this.canvas
.getObjects()
?.findIndex((obj) => obj.id === layer.fabricObjects?.[0]?.id) || 0;
if (this.oldFill) {
// 如果有旧填充,先获取旧的索引再移除旧填充
insertIndex =
this.canvas.getObjects()?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
this.canvas
.getObjects()
?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
removeCanvasObjectByObject(this.canvas, this.oldFill);
}
insertIndex = insertIndex == -1 ? 0 : insertIndex;
@@ -122,13 +127,17 @@ export class FillLayerBackgroundCommand extends Command {
.getObjects()
.findIndex(
(obj) =>
obj.id === this.originalfabricObjects[this.originalfabricObjects.length - 1]?.id
obj.id ===
this.originalfabricObjects[this.originalfabricObjects.length - 1]
?.id
) || 0;
if (this.oldFill) {
// 如果有旧填充,先获取旧的索引再移除旧填充
insertIndex =
this.canvas.getObjects()?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
this.canvas
.getObjects()
?.findIndex((obj) => obj.id === this.oldFill?.id) || 0;
removeCanvasObjectByObject(this.canvas, this.oldFill);
}
insertIndex = insertIndex == -1 ? 0 : insertIndex;
@@ -142,7 +151,9 @@ export class FillLayerBackgroundCommand extends Command {
if (!this.isRetimeUpdate) {
layer.fill = this.newFill.toObject(["id", "layerId"]);
layer.fillColor = this.fillColor;
this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layer.id);
this.canvasManager.thumbnailManager?.generateLayerThumbnail(
this.layer.id
);
// 重新排序
// 使用LayerSort工具重新排列画布对象如果可用
@@ -187,7 +198,10 @@ export class FillLayerBackgroundCommand extends Command {
.map((obj) => {
return findObjectById(this.canvas.value, obj.id)?.object || obj;
});
} else if (this.layer.fabricObjects && this.layer.fabricObjects.length > 0) {
} else if (
this.layer.fabricObjects &&
this.layer.fabricObjects.length > 0
) {
// 如果是普通图层直接返回其fabric对象
return this.layer.fabricObjects.map((obj) => {
return findObjectById(this.canvas.value, obj.id)?.object || obj;
@@ -204,11 +218,17 @@ export class FillLayerBackgroundCommand extends Command {
minTop = Infinity,
maxRight = -Infinity,
maxBottom = -Infinity;
console.log("计算当前所有对象的边界信息:===>", this.originalfabricObjects.length);
console.log(
"计算当前所有对象的边界信息:===>",
this.originalfabricObjects.length
);
this.originalfabricObjects?.forEach((obj) => {
const { object } = findObjectById(this.canvas, obj.id) || {};
if (object) {
const rect = object.getBoundingRect({ absolute: true, includeStroke: false });
const rect = object.getBoundingRect({
absolute: true,
includeStroke: false,
});
minLeft = Math.min(minLeft, rect.left);
minTop = Math.min(minTop, rect.top);
maxRight = Math.max(maxRight, rect.left + rect.width);

View File

@@ -224,7 +224,7 @@ export class AddObjectToLayerCommand extends Command {
isLocked: layer.locked || false, // 是否锁定
isVisible: layer.visible !== false, // 是否可见
eraser: layer.eraser || false, // 是否为橡皮擦
type: this.fabricObject.type || "object", // 对象类型
// type: this.fabricObject.type || "object", // 对象类型
selectable: true, // 设置对象可选择
evented: true, // 设置对象可事件
});

View File

@@ -1,6 +1,11 @@
import { Command } from "./Command";
import { fabric } from "fabric-with-all";
import { LayerType, OperationType, createLayer, findLayerRecursively } from "../utils/layerHelper";
import {
LayerType,
OperationType,
createLayer,
findLayerRecursively,
} from "../utils/layerHelper";
import {
generateId,
optimizeCanvasRendering,
@@ -34,7 +39,10 @@ export class RasterizeLayerCommand extends Command {
this.layerManager = options.layerManager;
// 查找目标图层
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
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;
@@ -94,7 +102,9 @@ export class RasterizeLayerCommand extends Command {
console.log(`✅ 图层 ${this.layer.name} 组合完成`);
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(this.rasterizedLayerId);
this.canvas?.thumbnailManager?.generateLayerThumbnail?.(
this.rasterizedLayerId
);
return this.rasterizedLayerId;
} catch (error) {
console.error("组合图层失败:", error);
@@ -330,7 +340,7 @@ export class RasterizeLayerCommand extends Command {
// 更新图像对象的图层关联
rasterizedImage.set({
id: this.resterizedId,
type: "image",
// type: "image",
layerId: this.rasterizedLayerId,
layerName: this.rasterizedLayer.name,
});
@@ -352,7 +362,10 @@ export class RasterizeLayerCommand extends Command {
*/
_replaceLayerInStructure() {
// 1.当前如果是子图层,则插入到子图层的位置
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
const { layer, parent } = findLayerRecursively(
this.layers.value,
this.layerId
);
let insertIndex = 0;
// 说明是子图层
@@ -373,7 +386,11 @@ export class RasterizeLayerCommand extends Command {
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);
this.layers.value[pIndex].children?.splice?.(
insertIndex,
1,
this.rasterizedLayer
);
} else {
this.layers.value.splice(insertIndex, 1, this.rasterizedLayer);
}
@@ -391,9 +408,14 @@ export class RasterizeLayerCommand extends Command {
async _getMaskObject() {
// 如果图层有clippingMask获取对应的fabric对象
if (this.layer?.clippingMask) {
const { object: maskObject } = findObjectById(this.canvas, this.layer.clippingMask.id);
const { object: maskObject } = findObjectById(
this.canvas,
this.layer.clippingMask.id
);
if (maskObject) {
console.log(`📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}`);
console.log(
`📎 找到遮罩对象: ${maskObject.id}, 类型: ${maskObject.type}`
);
return maskObject;
}
return await restoreFabricObject(this.layer.clippingMask);
@@ -439,7 +461,10 @@ export class ExportLayerToImageCommand extends Command {
this.layerManager = options.layerManager;
// 查找目标图层
const { layer, parent } = findLayerRecursively(this.layers.value, this.layerId);
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;
@@ -475,7 +500,10 @@ export class ExportLayerToImageCommand extends Command {
let clippingMaskFabricObject = null;
if (this.layer?.clippingMask) {
// 重新创建遮罩对象
clippingMaskFabricObject = await restoreFabricObject(this.layer?.clippingMask, this.canvas);
clippingMaskFabricObject = await restoreFabricObject(
this.layer?.clippingMask,
this.canvas
);
clippingMaskFabricObject.clipPath = null;
clippingMaskFabricObject.set({

View File

@@ -310,7 +310,11 @@ async function prepareForLiquify(targetObj) {
}
// 获取图层信息
const layerId = targetObj.layerId || props.canvas.activeLayerId?.value;
const layerId =
targetObj.layerId ||
canvasManager?.layerManager?.activeLayerId?.value ||
canvasManager.activeLayerId?.value ||
props.canvas.activeLayerId?.value;
targetLayerId.value = layerId;
try {
@@ -374,7 +378,10 @@ onMounted(() => {
});
// 创建状态管理器
stateManager.value = new LiquifyStateManager(props.canvas, realtimeUpdater.value);
stateManager.value = new LiquifyStateManager(
props.canvas,
realtimeUpdater.value
);
}
// 监听画布事件
@@ -443,7 +450,12 @@ function showPanel(event) {
return;
}
console.log("显示液化面板,目标对象:", targetObj.type, "图层ID:", targetLayerIdValue);
console.log(
"显示液化面板,目标对象:",
targetObj.type,
"图层ID:",
targetLayerIdValue
);
// 更新面板状态,但保持当前模式不变
// 只有在首次显示面板或面板已关闭时才重置模式
@@ -513,8 +525,8 @@ function showPanel(event) {
const status = props.liquifyManager.getStatus
? props.liquifyManager.getStatus()
: props.liquifyManager.enhancedManager
? props.liquifyManager.enhancedManager.getStatus()
: {};
? props.liquifyManager.enhancedManager.getStatus()
: {};
webglAvailable.value = status.isWebGLAvailable || false;
@@ -545,8 +557,8 @@ function showPanel(event) {
const status = props.liquifyManager.getStatus
? props.liquifyManager.getStatus()
: props.liquifyManager.enhancedManager
? props.liquifyManager.enhancedManager.getStatus()
: {};
? props.liquifyManager.enhancedManager.getStatus()
: {};
webglAvailable.value = status.isWebGLAvailable || false;
@@ -605,7 +617,11 @@ function setTargetObject(obj) {
// 确保对象有唯一ID
if (!obj.id && !obj.objectId && !obj.uid) {
obj.id = "liquify_target_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
obj.id =
"liquify_target_" +
Date.now() +
"_" +
Math.random().toString(36).substr(2, 9);
}
targetObject.value = obj;
@@ -673,7 +689,9 @@ function updateParam(paramName, value) {
`set${paramName.charAt(0).toUpperCase() + paramName.slice(1)}`
] === "function"
) {
props.liquifyManager[`set${paramName.charAt(0).toUpperCase() + paramName.slice(1)}`](value);
props.liquifyManager[
`set${paramName.charAt(0).toUpperCase() + paramName.slice(1)}`
](value);
} else {
console.warn(`❌ 液化管理器不支持设置参数: ${paramName}`);
}
@@ -756,9 +774,19 @@ async function getCurrentImageData(targetObject) {
tempCtx.drawImage(element, 0, 0, tempCanvas.width, tempCanvas.height);
// 获取ImageData
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
const imageData = tempCtx.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
console.log("✅ 成功获取当前图像状态,尺寸:", imageData.width, "x", imageData.height);
console.log(
"✅ 成功获取当前图像状态,尺寸:",
imageData.width,
"x",
imageData.height
);
return imageData;
} catch (error) {
console.warn("获取当前图像数据失败:", error);
@@ -837,7 +865,9 @@ async function handleMouseDown(event) {
const imageCoords = _convertFabricCoordsToImageCoords(pointer.x, pointer.y);
if (imageCoords) {
props.liquifyManager.startLiquifyOperation(imageCoords.x, imageCoords.y);
console.log(`开始液化操作,图像坐标: (${imageCoords.x}, ${imageCoords.y})`);
console.log(
`开始液化操作,图像坐标: (${imageCoords.x}, ${imageCoords.y})`
);
}
}
@@ -933,15 +963,27 @@ async function handleMouseUp() {
// 尝试从实时更新器获取当前图像数据
if (realtimeUpdater.value) {
try {
const currentImageElement = realtimeUpdater.value.getTargetObject()?._element;
const currentImageElement =
realtimeUpdater.value.getTargetObject()?._element;
if (currentImageElement) {
// 从当前图像元素创建ImageData
const tempCanvas = document.createElement("canvas");
tempCanvas.width = initialImageData.value.width;
tempCanvas.height = initialImageData.value.height;
const tempCtx = tempCanvas.getContext("2d");
tempCtx.drawImage(currentImageElement, 0, 0, tempCanvas.width, tempCanvas.height);
finalImageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
tempCtx.drawImage(
currentImageElement,
0,
0,
tempCanvas.width,
tempCanvas.height
);
finalImageData = tempCtx.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
console.log(
"✅ 从实时更新器获取最终图像数据成功,尺寸:",
@@ -962,8 +1004,19 @@ async function handleMouseUp() {
tempCanvas.width = initialImageData.value.width;
tempCanvas.height = initialImageData.value.height;
const tempCtx = tempCanvas.getContext("2d");
tempCtx.drawImage(currentTarget._element, 0, 0, tempCanvas.width, tempCanvas.height);
finalImageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
tempCtx.drawImage(
currentTarget._element,
0,
0,
tempCanvas.width,
tempCanvas.height
);
finalImageData = tempCtx.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
console.log(
"✅ 从目标对象获取最终图像数据成功,尺寸:",
@@ -1048,7 +1101,14 @@ async function applyLiquifyAtPoint(x, y) {
return;
}
console.log("原始坐标:", x, y, "转换后图像坐标:", imageCoords.x, imageCoords.y);
console.log(
"原始坐标:",
x,
y,
"转换后图像坐标:",
imageCoords.x,
imageCoords.y
);
// 获取当前参数
const params = {
@@ -1113,7 +1173,8 @@ async function applyLiquifyAtPoint(x, y) {
targetObject.value = updatedObject;
// 如果对象有新的ID也要更新ID
if (updatedObject.id || updatedObject.objectId || updatedObject.uid) {
targetObjectId.value = updatedObject.id || updatedObject.objectId || updatedObject.uid;
targetObjectId.value =
updatedObject.id || updatedObject.objectId || updatedObject.uid;
}
}
}
@@ -1127,7 +1188,8 @@ async function applyLiquifyAtPoint(x, y) {
if (avgOperationTime.value === 0) {
avgOperationTime.value = operationTime;
} else {
avgOperationTime.value = 0.7 * avgOperationTime.value + 0.3 * operationTime;
avgOperationTime.value =
0.7 * avgOperationTime.value + 0.3 * operationTime;
}
// 将性能指标传递给状态管理器
@@ -1267,7 +1329,9 @@ async function _replaceTargetWithNewImage(dataURL) {
if (layer.type === "background" || layer.isBackground) {
layer.fabricObject = img;
} else if (layer.fabricObjects) {
const objIndex = layer.fabricObjects.findIndex((obj) => obj.id === img.id);
const objIndex = layer.fabricObjects.findIndex(
(obj) => obj.id === img.id
);
if (objIndex !== -1) {
layer.fabricObjects[objIndex] = img;
}
@@ -1304,7 +1368,10 @@ function _convertFabricCoordsToImageCoords(fabricX, fabricY) {
const matrix = fabric.util.invertTransform(transform);
// 应用逆变换,将画布坐标转换为对象本地坐标
const localPoint = fabric.util.transformPoint(new fabric.Point(fabricX, fabricY), matrix);
const localPoint = fabric.util.transformPoint(
new fabric.Point(fabricX, fabricY),
matrix
);
// 获取图像的原始尺寸(未缩放前)
const imageWidth = originalImageData.value.width;
@@ -1340,7 +1407,12 @@ function _convertFabricCoordsToImageCoords(fabricX, fabricY) {
);
// 检查坐标是否在图像范围内
if (imageX < 0 || imageX >= imageWidth || imageY < 0 || imageY >= imageHeight) {
if (
imageX < 0 ||
imageX >= imageWidth ||
imageY < 0 ||
imageY >= imageHeight
) {
console.warn(
`坐标超出图像范围: (${imageX}, ${imageY}), 图像尺寸: ${imageWidth}x${imageHeight}`
);
@@ -1539,9 +1611,7 @@ function stopPressTimer() {
.fade-enter-active,
.fade-leave-active {
transition:
opacity 0.3s,
transform 0.3s;
transition: opacity 0.3s, transform 0.3s;
}
.fade-enter-from,
.fade-leave-to {

View File

@@ -218,6 +218,7 @@ onMounted(async () => {
isFixedErasable: props.isFixedErasable,
});
canvasManager.canvas.activeLayerId = activeLayerId;
canvasManager.activeLayerId = activeLayerId;
canvasManager.canvas.activeElementId = activeElementId;
// 创建命令管理器
@@ -1207,8 +1208,8 @@ defineExpose({
bottom: 1rem;
right: 1rem;
background: rgba(255, 255, 255, 0.7);
padding: .5rem 1rem;
border-radius: .4rem;
padding: 0.5rem 1rem;
border-radius: 0.4rem;
font-size: 1.4rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
color: #666;
@@ -1220,8 +1221,8 @@ defineExpose({
top: 1rem;
left: 1rem;
background: rgba(255, 255, 255, 0.8);
padding: .5rem 1rem;
border-radius: .4rem;
padding: 0.5rem 1rem;
border-radius: 0.4rem;
font-size: 1.2rem;
color: #666;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
@@ -1230,11 +1231,11 @@ defineExpose({
.reset-zoom {
margin-left: 1rem;
cursor: pointer;
padding: .2rem .5rem;
padding: 0.2rem 0.5rem;
font-size: 1.2rem;
border: 1px solid #ddd;
background: #f8f8f8;
border-radius: .3rem;
border-radius: 0.3rem;
}
.footer-actions {
@@ -1247,7 +1248,7 @@ defineExpose({
.share-btn,
.export-btn {
padding: .8rem 2rem;
padding: 0.8rem 2rem;
border: none;
border-radius: 2rem;
background-color: #000;
@@ -1310,7 +1311,7 @@ button:hover {
max-height: 90vh;
overflow-y: auto;
background-color: #fff;
border-radius: .8rem;
border-radius: 0.8rem;
padding: 2rem;
}
@@ -1337,11 +1338,11 @@ button:hover {
right: 1rem;
background: rgba(255, 255, 255, 0.9);
padding: 1rem;
border-radius: .4rem;
border-radius: 0.4rem;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
display: flex;
flex-direction: column;
gap: .8rem;
gap: 0.8rem;
z-index: 5;
}
@@ -1353,7 +1354,7 @@ button:hover {
background: #fff;
width: 35rem;
max-height: 85vh;
box-shadow: 0 .4rem 2rem rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
box-shadow: 0 0.4rem 2rem rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
backdrop-filter: blur(2px); /* 添加模糊效果 */
-webkit-backdrop-filter: blur(2px);
background-color: rgba(255, 255, 255, 0.95); /* 改为白色背景 */
@@ -1363,8 +1364,8 @@ button:hover {
&::before {
content: "";
position: absolute;
top: -.9rem;
right: .6rem;
top: -0.9rem;
right: 0.6rem;
width: 0;
height: 0;
border-left: 1rem solid transparent;
@@ -1388,7 +1389,7 @@ button:hover {
.layer-item,
.element-item {
padding: 1.2rem .8rem;
padding: 1.2rem 0.8rem;
}
.element-action-btn,

View File

@@ -903,7 +903,10 @@ export class LayerManager {
* @returns {Object|null} 图层对象或null
*/
getLayerById(layerId) {
const { layer } = findLayerRecursively(this.layers.value, layerId);
const { layer } = findLayerRecursively(
this.layers?.value ?? this.layers,
layerId
);
return layer;
}

View File

@@ -3,7 +3,7 @@ import { BrushManager } from "./brushes/brushManager";
import { BrushIndicator } from "./BrushIndicator";
import { ToolCommand } from "../commands/ToolCommands";
import { CreateTextCommand } from "../commands/TextCommands";
import { OperationType } from "../utils/layerHelper";
import { findLayerRecursively, OperationType } from "../utils/layerHelper";
import CanvasConfig from "../config/canvasConfig";
import { fabric } from "fabric-with-all";
import { InitLiquifyToolCommand } from "../commands/LiquifyCommands";
@@ -349,6 +349,11 @@ export class ToolManager {
// 保存先前的工具
this.previousTool = this.activeTool.value;
// 取消画布的选中状态
this.canvas?.discardActiveObject();
this.canvasManager?.layerManager?.updateLayersObjectsInteractivity?.();
this.canvas?.renderAll();
// 如果切换到非画笔工具,禁用笔刷指示器
if (!this._shouldShowBrushIndicator(toolId)) {
this._disableBrushIndicator();
@@ -665,7 +670,11 @@ export class ToolManager {
panelDetail.layerStatus = checkResult;
// 获取图层对象
const layer = this.layerManager.getLayerById(activeLayerId);
// const layer = this.layerManager.getLayerById(activeLayerId);
const { layer } = findLayerRecursively(
this.layerManager.layers?.value ?? this.layerManager.layers,
activeLayerId
);
// 检查图层是否为空
if (!checkResult.isEmpty) {
@@ -844,7 +853,12 @@ export class ToolManager {
*/
async _startLiquify(layerId) {
// 获取图层信息
const layer = this.layerManager.getLayerById(layerId);
// const layer = this.layerManager.getLayerById(layerId);
const { layer } = findLayerRecursively(
this.layerManager.layers?.value ?? this.layerManager.layers,
layerId
);
if (!layer) {
Modal.error({
title: "图层错误",
@@ -1122,7 +1136,11 @@ export class ToolManager {
target.type === "textbox")
) {
// 获取对应的图层
const layer = this.layerManager.getLayerById(target.layerId);
// const layer = this.layerManager.getLayerById(target.layerId);
const { layer } = findLayerRecursively(
this.layerManager.layers?.value ?? this.layerManager.layers,
target.layerId
);
if (layer) {
// 显示文本编辑面板
this.showTextEditor(target, layer);

View File

@@ -4,7 +4,7 @@
*/
import { LiquifyWebGLManager } from "./LiquifyWebGLManager";
import { LiquifyCPUManager } from "./LiquifyCPUManager";
import { findInChildLayers, LayerType } from "../../utils/layerHelper";
import { findLayerRecursively, LayerType } from "../../utils/layerHelper";
export class EnhancedLiquifyManager {
/**
@@ -140,7 +140,10 @@ export class EnhancedLiquifyManager {
// 处理传入的是图层ID的情况
if (typeof target === "string") {
targetLayerId = target;
const layer = this.layerManager.getLayerById(targetLayerId);
const { layer } = findLayerRecursively(
this.layerManager.layers?.value ?? this.layerManager.layers,
targetLayerId
);
// 检查图层是否存在和是否有对象
let hasObjects = false;
@@ -160,7 +163,7 @@ export class EnhancedLiquifyManager {
} else if (typeof target === "object") {
// 传入的是对象
targetObject = target;
const { layer } = findInChildLayers(
const { layer } = findLayerRecursively(
this.layerManager.layers?.value ?? this.layerManager.layers,
targetObject.layerId
);
@@ -216,7 +219,9 @@ export class EnhancedLiquifyManager {
// 计算图像大小
const pixelCount = imageData.width * imageData.height;
console.log(`液化选择渲染器: 图像大小=${pixelCount}像素, WebGL可用=${this.isWebGLAvailable}`);
console.log(
`液化选择渲染器: 图像大小=${pixelCount}像素, WebGL可用=${this.isWebGLAvailable}`
);
// 默认使用CPU渲染器
this.activeRenderer = this.cpuRenderer;
@@ -247,7 +252,11 @@ export class EnhancedLiquifyManager {
this.activeRenderer = this.webglRenderer;
this.renderMode = "webgl";
} else {
console.log(`液化功能: 使用CPU渲染模式${!this.isWebGLAvailable ? " (WebGL不可用)" : ""}`);
console.log(
`液化功能: 使用CPU渲染模式${
!this.isWebGLAvailable ? " (WebGL不可用)" : ""
}`
);
}
}
@@ -312,11 +321,16 @@ export class EnhancedLiquifyManager {
this.params[param] = value;
// 同步更新当前渲染器 - 关键修复:确保参数正确传递
if (this.activeRenderer && typeof this.activeRenderer.setParam === "function") {
if (
this.activeRenderer &&
typeof this.activeRenderer.setParam === "function"
) {
console.log(`EnhancedLiquifyManager 设置参数: ${param}=${value}`);
this.activeRenderer.setParam(param, value);
} else {
console.warn(`EnhancedLiquifyManager: 无法设置参数 ${param},渲染器未就绪`);
console.warn(
`EnhancedLiquifyManager: 无法设置参数 ${param},渲染器未就绪`
);
}
return true;
@@ -371,17 +385,25 @@ export class EnhancedLiquifyManager {
* @param {Number} y 初始Y坐标
*/
startLiquifyOperation(x, y) {
if (this.activeRenderer && typeof this.activeRenderer.startDeformation === "function") {
if (
this.activeRenderer &&
typeof this.activeRenderer.startDeformation === "function"
) {
this.activeRenderer.startDeformation(x, y);
}
console.log(`开始液化操作,渲染模式=${this.renderMode}, 初始点: (${x}, ${y})`);
console.log(
`开始液化操作,渲染模式=${this.renderMode}, 初始点: (${x}, ${y})`
);
}
/**
* 结束液化操作
*/
endLiquifyOperation() {
if (this.activeRenderer && typeof this.activeRenderer.endDeformation === "function") {
if (
this.activeRenderer &&
typeof this.activeRenderer.endDeformation === "function"
) {
this.activeRenderer.endDeformation();
}
console.log(`结束液化操作,渲染模式=${this.renderMode}`);
@@ -424,7 +446,9 @@ export class EnhancedLiquifyManager {
// 坐标边界检查
if (x < 0 || x >= imageWidth || y < 0 || y >= imageHeight) {
console.warn(`液化坐标超出图像范围: (${x}, ${y}), 图像尺寸: ${imageWidth}x${imageHeight}`);
console.warn(
`液化坐标超出图像范围: (${x}, ${y}), 图像尺寸: ${imageWidth}x${imageHeight}`
);
return null;
}
@@ -489,7 +513,9 @@ export class EnhancedLiquifyManager {
console.log(
`液化性能数据: 模式=${this.renderMode}, 平均耗时=${avgTime.toFixed(
2
)}ms, 图像尺寸=${this.originalImageData?.width}x${this.originalImageData?.height}`
)}ms, 图像尺寸=${this.originalImageData?.width}x${
this.originalImageData?.height
}`
);
}
@@ -542,7 +568,11 @@ export class EnhancedLiquifyManager {
}
// 获取图层
const layer = this.layerManager.getLayerById(layerId);
// const layer = this.layerManager.getLayerById(layerId);
const { layer } = findLayerRecursively(
this.layerManager.layers?.value ?? this.layerManager.layers,
layerId
);
if (!layer) {
return {
valid: false,
@@ -581,7 +611,8 @@ export class EnhancedLiquifyManager {
const singleObject = objectsToCheck.length === 1;
const isImage =
singleObject &&
(objectsToCheck[0].type === "image" || objectsToCheck[0].type === "rasterized-layer");
(objectsToCheck[0].type === "image" ||
objectsToCheck[0].type === "rasterized-layer");
// 检查是否为组
const isGroup =
@@ -631,14 +662,19 @@ export class EnhancedLiquifyManager {
tempCanvas.height = fabricObject.height;
const tempCtx = tempCanvas.getContext("2d");
console.log(`创建临时Canvas尺寸: ${tempCanvas.width}x${tempCanvas.height}`);
console.log(
`创建临时Canvas尺寸: ${tempCanvas.width}x${tempCanvas.height}`
);
// 处理不同的图像源
if (fabricObject._element) {
console.log("使用 _element 绘制图像");
// 检查_element是否有效
if (!fabricObject._element.complete && fabricObject._element.tagName === "IMG") {
if (
!fabricObject._element.complete &&
fabricObject._element.tagName === "IMG"
) {
console.log("图像未加载完成,等待加载...");
fabricObject._element.onload = () => {
try {
@@ -649,7 +685,12 @@ export class EnhancedLiquifyManager {
fabricObject.width,
fabricObject.height
);
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
const imageData = tempCtx.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
console.log("✅ 图像加载完成后获取数据成功");
resolve(imageData);
} catch (error) {
@@ -664,8 +705,17 @@ export class EnhancedLiquifyManager {
}
// 直接绘制已加载的图像
tempCtx.drawImage(fabricObject._element, 0, 0, fabricObject.width, fabricObject.height);
} else if (fabricObject.getSrc && typeof fabricObject.getSrc === "function") {
tempCtx.drawImage(
fabricObject._element,
0,
0,
fabricObject.width,
fabricObject.height
);
} else if (
fabricObject.getSrc &&
typeof fabricObject.getSrc === "function"
) {
console.log("使用 getSrc() 方法获取图像源");
// 通过URL创建图像
@@ -674,11 +724,24 @@ export class EnhancedLiquifyManager {
img.onload = () => {
try {
console.log(`图像加载成功,原始尺寸: ${img.naturalWidth}x${img.naturalHeight}`);
console.log(
`图像加载成功,原始尺寸: ${img.naturalWidth}x${img.naturalHeight}`
);
tempCtx.drawImage(img, 0, 0, fabricObject.width, fabricObject.height);
tempCtx.drawImage(
img,
0,
0,
fabricObject.width,
fabricObject.height
);
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
const imageData = tempCtx.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
console.log("✅ 通过URL获取图像数据成功");
resolve(imageData);
@@ -706,9 +769,20 @@ export class EnhancedLiquifyManager {
img.onload = () => {
try {
tempCtx.drawImage(img, 0, 0, fabricObject.width, fabricObject.height);
tempCtx.drawImage(
img,
0,
0,
fabricObject.width,
fabricObject.height
);
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
const imageData = tempCtx.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
console.log("✅ 通过src属性获取图像数据成功");
resolve(imageData);
@@ -728,13 +802,20 @@ export class EnhancedLiquifyManager {
return;
} else {
console.error("无法找到有效的图像源");
reject(new Error("图像对象缺少有效的图像源_element, getSrc, 或 src"));
reject(
new Error("图像对象缺少有效的图像源_element, getSrc, 或 src")
);
return;
}
// 如果走到这里说明使用了_element直接绘制
try {
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
const imageData = tempCtx.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
console.log(
`✅ 获取图像数据成功: 对象尺寸=${fabricObject.width}x${fabricObject.height}, ` +

View File

@@ -95,7 +95,8 @@ export const BlendMode = {
export function isGroupLayer(layer) {
if (!layer) return false;
return (
layer.type === LayerType.GROUP || (Array.isArray(layer.children) && layer.children.length > 0)
layer.type === LayerType.GROUP ||
(Array.isArray(layer.children) && layer.children.length > 0)
);
}
@@ -106,7 +107,11 @@ export function isGroupLayer(layer) {
* @param {Object} options 其他选项
* @returns {Object} 创建的图层对象
*/
export function createLayerFromFabricObject(fabricObject, layerType = "bitmap", options = {}) {
export function createLayerFromFabricObject(
fabricObject,
layerType = "bitmap",
options = {}
) {
if (!fabricObject) return null;
// 确定图层类型
@@ -132,7 +137,9 @@ export function createLayerFromFabricObject(fabricObject, layerType = "bitmap",
type: type,
name:
options.name ||
`${fabricObject.type.charAt(0).toUpperCase() + fabricObject.type.slice(1)} 图层`,
`${
fabricObject.type.charAt(0).toUpperCase() + fabricObject.type.slice(1)
} 图层`,
parentId: options.parentId || null,
});
@@ -159,7 +166,9 @@ export function createLayerFromFabricObject(fabricObject, layerType = "bitmap",
*/
export function createLayer(options = {}) {
const id =
options.id || generateId("layer_") || `layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
options.id ||
generateId("layer_") ||
`layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
return {
id: id,
// 图层基本属性
@@ -199,7 +208,8 @@ export function createLayer(options = {}) {
* @returns {Object} 背景图层对象
*/
export function createBackgroundLayer(options = {}) {
const id = options.id || `bg_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
const id =
options.id || `bg_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
return {
id: id,
// 图层基本属性
@@ -390,7 +400,9 @@ export function createSmartObjectLayer(options = {}) {
* @returns {Object} 固定图层对象
*/
export function createFixedLayer(options = {}) {
const id = options.id || `fixed_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
const id =
options.id ||
`fixed_layer_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
return {
id: id,
// 图层基本属性
@@ -433,7 +445,9 @@ export function cloneLayer(layer) {
// 复制 fabric 对象 (如果存在)
if (Array.isArray(layer.fabricObjects)) {
clonedLayer.fabricObjects = layer.fabricObjects.map((obj) => {
return obj && typeof obj.clone === "function" ? obj.clone() : JSON.parse(JSON.stringify(obj));
return obj && typeof obj.clone === "function"
? obj.clone()
: JSON.parse(JSON.stringify(obj));
});
}