From c4cb34e5302873de9f253122d88af35273b5f6c1 Mon Sep 17 00:00:00 2001 From: zhangyh Date: Thu, 6 Nov 2025 11:40:33 +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=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CanvasEditor/commands/LiquifyCommands.js | 120 ++++++++---------- 1 file changed, 55 insertions(+), 65 deletions(-) diff --git a/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js b/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js index a8afc578..2ecda7b1 100644 --- a/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js +++ b/src/component/Canvas/CanvasEditor/commands/LiquifyCommands.js @@ -1,6 +1,7 @@ import { Command, FunctionCommand } from "./Command"; import { getLiquifyReferenceManager } from "../managers/LiquifyReferenceManager"; import { optimizeCanvasRendering } from "../utils/helper"; +import { fabric } from "fabric-with-all"; /** * 液化命令基类 @@ -129,6 +130,7 @@ export class LiquifyCommand extends Command { /** * 使用变形结果更新对象 + * 优化:直接使用 setElement 更新现有对象,避免创建新对象和替换操作 * @private */ async _updateObjectWithResult() { @@ -144,16 +146,27 @@ export class LiquifyCommand extends Command { // 使用优化渲染工具,避免图层闪烁 await optimizeCanvasRendering(this.canvas, async () => { - // 预先加载图像,确保完全加载后再替换 - await new Promise((resolve, reject) => { - fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { - if (!img) { - reject(new Error("图像加载失败")); - return; - } + // 预加载图像元素,确保完全加载后再更新 + await this._updateObjectElementDirectly(tempCanvas.toDataURL()); + }); - // 保留原对象的属性 - img.set({ + return true; + } + + /** + * 直接更新对象的图像元素,避免对象替换造成的图层闪烁 + * @param {String} imageDataURL 图像数据的 DataURL + * @private + */ + async _updateObjectElementDirectly(imageDataURL) { + return new Promise((resolve, reject) => { + // 创建 HTMLImageElement 并预加载 + const imgElement = new Image(); + + imgElement.onload = () => { + try { + // 保存当前对象状态(非图像属性) + const currentState = { left: this.targetObject.left, top: this.targetObject.top, scaleX: this.targetObject.scaleX, @@ -162,31 +175,41 @@ export class LiquifyCommand extends Command { 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("图像加载失败")); - }); + // 直接更新现有对象的图像元素,保持对象引用不变 + if (this.targetObject.setElement) { + this.targetObject.setElement(imgElement); + } else if (this.targetObject._element) { + this.targetObject._element = imgElement; + this.targetObject._originalElement = imgElement; } - }); - }); - }); - return true; + // 恢复对象属性(setElement 可能会重置一些属性) + this.targetObject.set(currentState); + + // 标记对象需要重新渲染 + this.targetObject.dirty = true; + this.targetObject.setCoords(); + + resolve(); + } catch (error) { + console.error("更新对象元素失败:", error); + reject(error); + } + }; + + imgElement.onerror = () => { + reject(new Error("图像加载失败")); + }; + + // 开始加载图像 + imgElement.src = imageDataURL; + }); } /** - * 安全地替换对象,避免图层闪烁 + * 安全地替换对象,避免图层闪烁(保留作为备用方法) * @param {Object} newImg 新的fabric图像对象 * @private */ @@ -323,6 +346,7 @@ export class LiquifyDeformCommand extends LiquifyCommand { /** * 使用图像数据更新对象 + * 优化:直接使用 setElement 更新现有对象,避免创建新对象和替换操作 * @param {ImageData} imageData 图像数据 * @private */ @@ -336,47 +360,13 @@ export class LiquifyDeformCommand extends LiquifyCommand { // 使用优化渲染工具,避免图层闪烁 await optimizeCanvasRendering(this.canvas, async () => { - // 预先加载图像,确保完全加载后再替换 - await new Promise((resolve, reject) => { - fabric.Image.fromURL(tempCanvas.toDataURL(), (img) => { - if (!img) { - reject(new Error("图像加载失败")); - return; - } - - // 保留原对象的变换属性 - 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("图像加载失败")); - }); - } - }); - }); + // 直接更新对象元素,避免对象替换 + await this._updateObjectElementDirectly(tempCanvas.toDataURL()); }); } /** - * 安全地替换变形对象,避免图层闪烁 + * 安全地替换变形对象,避免图层闪烁(保留作为备用方法) * @param {Object} newImg 新的fabric图像对象 * @private */