From dcd734c402a5cddfcdf46934a50da1b94e41ed2f Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 16 Jan 2025 09:14:04 +1100 Subject: [PATCH] fix(ui): hide layer when previewing filter Previously, when previewing a filter on a layer with some transparency or a filter that changes the alpha, the preview was rendered on top of the layer. The preview blended with the layer, which isn't right. In this change, the layer is hidden during the preview, and when the filter finishes (having been applied or canceled - the two possible paths), the layer is shown. Technically, we are hiding and showing the layer's object renderer's konva group, which contains the layer's "real" data. Another small change was made to prevent a flash of empty layer, by waiting to destroy a previous filter preview image until the new preview image is ready to display. --- .../CanvasEntity/CanvasEntityFilterer.ts | 19 +++++++++++++++---- .../CanvasEntityObjectRenderer.ts | 8 ++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityFilterer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityFilterer.ts index 3c949560a6b..e8d8568fb41 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityFilterer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityFilterer.ts @@ -297,10 +297,9 @@ export class CanvasEntityFilterer extends CanvasModuleBase { const imageState = imageDTOToImageObject(filterResult.value); this.$imageState.set(imageState); - // Destroy any existing masked image and create a new one - if (this.imageModule) { - this.imageModule.destroy(); - } + // Stash the existing image module - we will destroy it after the new image is rendered to prevent a flash + // of an empty layer + const oldImageModule = this.imageModule; this.imageModule = new CanvasObjectImage(imageState, this); @@ -309,6 +308,16 @@ export class CanvasEntityFilterer extends CanvasModuleBase { this.konva.group.add(this.imageModule.konva.group); + // The filtered image have some transparency, so we need to hide the objects of the parent entity to prevent the + // two images from blending. We will show the objects again in the teardown method, which is always called after + // the filter finishes (applied or canceled). + this.parent.renderer.hideObjects(); + + if (oldImageModule) { + // Destroy the old image module now that the new one is rendered + oldImageModule.destroy(); + } + // The porcessing is complete, set can set the last processed hash and isProcessing to false this.$lastProcessedHash.set(hash); @@ -424,6 +433,8 @@ export class CanvasEntityFilterer extends CanvasModuleBase { teardown = () => { this.unsubscribe(); + // Re-enable the objects of the parent entity + this.parent.renderer.showObjects(); this.konva.group.remove(); // The reset must be done _after_ unsubscribing from listeners, in case the listeners would otherwise react to // the reset. For example, if auto-processing is enabled and we reset the state, it may trigger processing. diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts index 15a4a35fcd4..18e7e7f0e55 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts @@ -185,6 +185,14 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase { return didRender; }; + hideObjects = () => { + this.konva.objectGroup.hide(); + }; + + showObjects = () => { + this.konva.objectGroup.show(); + }; + adoptObjectRenderer = (renderer: AnyObjectRenderer) => { this.renderers.set(renderer.id, renderer); renderer.konva.group.moveTo(this.konva.objectGroup);