From de568f4f851ae13a5c9899b7f018cd219c8bc3ab Mon Sep 17 00:00:00 2001 From: zhangyh Date: Thu, 6 Nov 2025 11:04:14 +0800 Subject: [PATCH] =?UTF-8?q?bugfix:=20=E6=B6=B2=E5=8C=96=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E9=97=AA=E7=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CanvasEditor/commands/LiquifyCommands.js | 240 +++++++++++------- 1 file changed, 153 insertions(+), 87 deletions(-) diff --git a/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js b/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js index d6106c8b..a8afc578 100644 --- a/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js +++ b/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js @@ -1,5 +1,6 @@ import { Command, FunctionCommand } from "./Command"; import { getLiquifyReferenceManager } from "../managers/LiquifyReferenceManager"; +import { optimizeCanvasRendering } from "../utils/helper"; /** * 液化命令基类 @@ -59,9 +60,7 @@ export class LiquifyCommand extends Command { // 更新画布上的对象 await this._updateObjectWithResult(); - - // 刷新Canvas - this.canvas.renderAll(); + // 注意:_updateObjectWithResult 内部已使用 optimizeCanvasRendering,会自动渲染 return this.resultData; } @@ -142,48 +141,82 @@ export class LiquifyCommand extends Command { const tempCtx = tempCanvas.getContext("2d"); tempCtx.putImageData(this.resultData, 0, 0); console.log("临时Canvas创建成功 _updateObjectWithResult", this.resultData); - // 更新Fabric图像 - await new Promise((resolve) => { - fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { - // 保留原对象的属性 - img.set({ - left: this.targetObject.left, - top: this.targetObject.top, - scaleX: this.targetObject.scaleX, - scaleY: this.targetObject.scaleY, - angle: this.targetObject.angle, - flipX: this.targetObject.flipX, - flipY: this.targetObject.flipY, - opacity: this.targetObject.opacity, - }); - - // 替换Canvas上的对象 - const index = this.canvas.getObjects().indexOf(this.targetObject); - if (index !== -1) { - this.canvas.remove(this.targetObject); - this.canvas.insertAt(img, index); - this.targetObject = img; - } - - // 确保图层引用更新 - const layer = this.layerManager.getLayerById(this.targetLayerId); - if (layer) { - if (layer.type === "background" && layer.fabricObject === this.targetObject) { - layer.fabricObject = img; - } else if (layer.fabricObjects) { - const objIndex = layer.fabricObjects.indexOf(this.targetObject); - if (objIndex !== -1) { - layer.fabricObjects[objIndex] = img; - } + + // 使用优化渲染工具,避免图层闪烁 + await optimizeCanvasRendering(this.canvas, async () => { + // 预先加载图像,确保完全加载后再替换 + await new Promise((resolve, reject) => { + fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { + if (!img) { + reject(new Error("图像加载失败")); + return; } - } - resolve(); + // 保留原对象的属性 + img.set({ + left: this.targetObject.left, + top: this.targetObject.top, + scaleX: this.targetObject.scaleX, + scaleY: this.targetObject.scaleY, + angle: this.targetObject.angle, + flipX: this.targetObject.flipX, + flipY: this.targetObject.flipY, + opacity: this.targetObject.opacity, + }); + + // 确保图像已完全加载(通过检查元素) + if (img._element && img._element.complete) { + this._replaceObjectSafely(img); + resolve(); + } else { + // 如果图像还未加载完成,等待加载 + img.on("loaded", () => { + this._replaceObjectSafely(img); + resolve(); + }); + img.on("error", (error) => { + reject(error || new Error("图像加载失败")); + }); + } + }); }); }); return true; } + + /** + * 安全地替换对象,避免图层闪烁 + * @param {Object} newImg 新的fabric图像对象 + * @private + */ + _replaceObjectSafely(newImg) { + // 保存旧对象引用,用于更新图层引用 + const oldObject = this.targetObject; + + // 替换Canvas上的对象 + const index = this.canvas.getObjects().indexOf(oldObject); + if (index !== -1) { + // 在禁用自动渲染的情况下,先插入新对象,再移除旧对象 + // 这样可以避免中间出现空白(因为renderOnAddRemove已被禁用) + this.canvas.insertAt(newImg, index); + this.canvas.remove(oldObject); + this.targetObject = newImg; + } + + // 确保图层引用更新 + const layer = this.layerManager.getLayerById(this.targetLayerId); + if (layer) { + if (layer.type === "background" && layer.fabricObject === oldObject) { + layer.fabricObject = newImg; + } else if (layer.fabricObjects) { + const objIndex = layer.fabricObjects.indexOf(oldObject); + if (objIndex !== -1) { + layer.fabricObjects[objIndex] = newImg; + } + } + } + } } /** @@ -271,8 +304,8 @@ export class LiquifyDeformCommand extends LiquifyCommand { // 应用变形结果 await this._updateObjectWithImageData(this.afterData); + // 注意:_updateObjectWithImageData 内部已使用 optimizeCanvasRendering,会自动渲染 - this.canvas.renderAll(); return this.afterData; } @@ -283,8 +316,8 @@ export class LiquifyDeformCommand extends LiquifyCommand { // 恢复到变形前的状态 await this._updateObjectWithImageData(this.beforeData); + // 注意:_updateObjectWithImageData 内部已使用 optimizeCanvasRendering,会自动渲染 - this.canvas.renderAll(); return true; } @@ -294,59 +327,92 @@ export class LiquifyDeformCommand extends LiquifyCommand { * @private */ async _updateObjectWithImageData(imageData) { - return new Promise((resolve) => { - // 创建临时canvas - const tempCanvas = document.createElement("canvas"); - tempCanvas.width = imageData.width; - tempCanvas.height = imageData.height; - const tempCtx = tempCanvas.getContext("2d"); - tempCtx.putImageData(imageData, 0, 0); + // 创建临时canvas + const tempCanvas = document.createElement("canvas"); + tempCanvas.width = imageData.width; + tempCanvas.height = imageData.height; + const tempCtx = tempCanvas.getContext("2d"); + tempCtx.putImageData(imageData, 0, 0); - // 从canvas创建新的fabric图像 - fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { - // 保留原对象的变换属性 - img.set({ - left: this.targetObject.left, - top: this.targetObject.top, - scaleX: this.targetObject.scaleX, - scaleY: this.targetObject.scaleY, - angle: this.targetObject.angle, - flipX: this.targetObject.flipX, - flipY: this.targetObject.flipY, - opacity: this.targetObject.opacity, - }); - - // 替换canvas上的对象 - const index = this.canvas.getObjects().indexOf(this.targetObject); - if (index !== -1) { - this.canvas.remove(this.targetObject); - this.canvas.insertAt(img, index); - this.targetObject = img; - - // 更新图层引用 - const layer = this.layerManager.getLayerById(this.targetLayerId); - if (layer) { - if ( - layer.type === "background" && - (layer.fabricObject === this.savedState?.originalObject || - layer.fabricObject === this.targetObject) - ) { - layer.fabricObject = img; - } else if (layer.fabricObjects) { - const objIndex = layer.fabricObjects.findIndex( - (obj) => obj === this.savedState?.originalObject || obj === this.targetObject - ); - if (objIndex !== -1) { - layer.fabricObjects[objIndex] = img; - } - } + // 使用优化渲染工具,避免图层闪烁 + await optimizeCanvasRendering(this.canvas, async () => { + // 预先加载图像,确保完全加载后再替换 + await new Promise((resolve, reject) => { + fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { + if (!img) { + reject(new Error("图像加载失败")); + return; } - } - resolve(); + // 保留原对象的变换属性 + img.set({ + left: this.targetObject.left, + top: this.targetObject.top, + scaleX: this.targetObject.scaleX, + scaleY: this.targetObject.scaleY, + angle: this.targetObject.angle, + flipX: this.targetObject.flipX, + flipY: this.targetObject.flipY, + opacity: this.targetObject.opacity, + }); + + // 确保图像已完全加载 + if (img._element && img._element.complete) { + this._replaceDeformObjectSafely(img); + resolve(); + } else { + // 如果图像还未加载完成,等待加载 + img.on("loaded", () => { + this._replaceDeformObjectSafely(img); + resolve(); + }); + img.on("error", (error) => { + reject(error || new Error("图像加载失败")); + }); + } + }); }); }); } + + /** + * 安全地替换变形对象,避免图层闪烁 + * @param {Object} newImg 新的fabric图像对象 + * @private + */ + _replaceDeformObjectSafely(newImg) { + // 保存旧对象引用,用于更新图层引用 + const oldObject = this.targetObject; + + // 替换Canvas上的对象 + const index = this.canvas.getObjects().indexOf(oldObject); + if (index !== -1) { + // 在禁用自动渲染的情况下,先插入新对象,再移除旧对象 + // 这样可以避免中间出现空白 + this.canvas.insertAt(newImg, index); + this.canvas.remove(oldObject); + this.targetObject = newImg; + } + + // 更新图层引用 + const layer = this.layerManager.getLayerById(this.targetLayerId); + if (layer) { + if ( + layer.type === "background" && + (layer.fabricObject === this.savedState?.originalObject || + layer.fabricObject === oldObject) + ) { + layer.fabricObject = newImg; + } else if (layer.fabricObjects) { + const objIndex = layer.fabricObjects.findIndex( + (obj) => obj === this.savedState?.originalObject || obj === oldObject + ); + if (objIndex !== -1) { + layer.fabricObjects[objIndex] = newImg; + } + } + } + } } /**