From 22d574c92a98c8a1364a9cf25d41168144262097 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 4 Jul 2025 17:24:40 +1000 Subject: [PATCH] feat(ui): canvas metadata recall --- invokeai/frontend/web/public/locales/en.json | 2 +- .../src/features/controlLayers/store/types.ts | 2 +- .../ImageMetadataActions.tsx | 1 + .../web/src/features/metadata/parsing.tsx | 41 ++++++++++++++++++- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index fff29142fd..253e351817 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -762,7 +762,7 @@ "vae": "VAE", "width": "Width", "workflow": "Workflow", - "canvasV2Metadata": "Canvas" + "canvasV2Metadata": "Canvas Layers" }, "modelManager": { "active": "active", diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 88d24d703d..9bff95d850 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -599,7 +599,7 @@ export const zCanvasMetadata = z.object({ rasterLayers: z.array(zCanvasRasterLayerState), controlLayers: z.array(zCanvasControlLayerState), regionalGuidance: z.array(zCanvasRegionalGuidanceState), - referenceImages: z.array(zRefImageState), + // referenceImages: z.array(zRefImageState), }); export type CanvasMetadata = z.infer; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx index e8d9f4f4f2..10fe9d1a61 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx @@ -55,6 +55,7 @@ const ImageMetadataActions = (props: Props) => { + ); diff --git a/invokeai/frontend/web/src/features/metadata/parsing.tsx b/invokeai/frontend/web/src/features/metadata/parsing.tsx index f6c6b9d2d4..9acecd1023 100644 --- a/invokeai/frontend/web/src/features/metadata/parsing.tsx +++ b/invokeai/frontend/web/src/features/metadata/parsing.tsx @@ -5,7 +5,7 @@ import { useAppStore } from 'app/store/storeHooks'; import { WrappedError } from 'common/util/result'; import { get, isArray, isString } from 'es-toolkit/compat'; import { getPrefixedId } from 'features/controlLayers/konva/util'; -import { bboxHeightChanged, bboxWidthChanged } from 'features/controlLayers/store/canvasSlice'; +import { bboxHeightChanged, bboxWidthChanged, canvasMetadataRecalled } from 'features/controlLayers/store/canvasSlice'; import { loraAllDeleted, loraRecalled } from 'features/controlLayers/store/lorasSlice'; import { negativePrompt2Changed, @@ -32,7 +32,7 @@ import { shouldConcatPromptsChanged, vaeSelected, } from 'features/controlLayers/store/paramsSlice'; -import type { LoRA } from 'features/controlLayers/store/types'; +import { type CanvasMetadata, type LoRA, zCanvasMetadata } from 'features/controlLayers/store/types'; import type { ModelIdentifierField } from 'features/nodes/types/common'; import { zModelIdentifierField } from 'features/nodes/types/common'; import { zModelIdentifier } from 'features/nodes/types/v2/common'; @@ -732,6 +732,42 @@ const LoRAs: CollectionMetadataHandler = { }; //#endregion LoRAs +//#region CanvasLayers +const CanvasLayers: SingleMetadataHandler = { + [SingleMetadataKey]: true, + type: 'CanvasLayers', + parse: async (metadata) => { + const raw = getProperty(metadata, 'canvas_v2_metadata'); + // This validator fetches all referenced images. If any do not exist, validation fails. The logic for this is in + // the zImageWithDims schema. + const parsed = await zCanvasMetadata.parseAsync(raw); + return Promise.resolve(parsed); + }, + recall: (value, store) => { + if ( + value.controlLayers.length === 0 && + value.rasterLayers.length === 0 && + value.inpaintMasks.length === 0 && + value.regionalGuidance.length === 0 + ) { + // Nothing to recall + return; + } + store.dispatch(canvasMetadataRecalled(value)); + }, + LabelComponent: () => , + ValueComponent: ({ value }: SingleMetadataValueProps) => { + const { t } = useTranslation(); + const count = + value.controlLayers.length + + value.rasterLayers.length + + value.inpaintMasks.length + + value.regionalGuidance.length; + return ; + }, +}; +//#endregion CanvasLayers + export const MetadataHandlers = { CreatedBy, GenerationMode, @@ -760,6 +796,7 @@ export const MetadataHandlers = { MainModel, VAEModel, LoRAs, + CanvasLayers, // TODO: // Ref images // controlNet: parseControlNet,