mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): support recalling canvas metadata
- Add parser, recaller and handler - Add redux action to rehydrate the whole shebang at once
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
} from 'features/controlLayers/store/selectors';
|
||||
import type {
|
||||
CanvasInpaintMaskState,
|
||||
CanvasMetadata,
|
||||
FillStyle,
|
||||
RegionalGuidanceReferenceImageState,
|
||||
RgbColor,
|
||||
@@ -1036,6 +1037,16 @@ export const canvasSlice = createSlice({
|
||||
break;
|
||||
}
|
||||
},
|
||||
canvasMetadataRecalled: (state, action: PayloadAction<CanvasMetadata>) => {
|
||||
const newState = resetState(state);
|
||||
const { controlLayers, inpaintMasks, rasterLayers, referenceImages, regionalGuidance } = action.payload;
|
||||
newState.controlLayers.entities = controlLayers;
|
||||
newState.inpaintMasks.entities = inpaintMasks;
|
||||
newState.rasterLayers.entities = rasterLayers;
|
||||
newState.referenceImages.entities = referenceImages;
|
||||
newState.regionalGuidance.entities = regionalGuidance;
|
||||
return newState;
|
||||
},
|
||||
canvasUndo: () => {},
|
||||
canvasRedo: () => {},
|
||||
canvasClearHistory: () => {},
|
||||
@@ -1063,25 +1074,30 @@ export const canvasSlice = createSlice({
|
||||
});
|
||||
|
||||
builder.addCase(canvasReset, (state) => {
|
||||
const newState = getInitialState();
|
||||
|
||||
// We need to retain the optimal dimension across resets, as it is changed only when the model changes. Copy it
|
||||
// from the old state, then recalculate the bbox size & scaled size.
|
||||
newState.bbox.optimalDimension = state.bbox.optimalDimension;
|
||||
const rect = calculateNewSize(
|
||||
newState.bbox.aspectRatio.value,
|
||||
newState.bbox.optimalDimension * newState.bbox.optimalDimension
|
||||
);
|
||||
newState.bbox.rect.width = rect.width;
|
||||
newState.bbox.rect.height = rect.height;
|
||||
syncScaledSize(newState);
|
||||
|
||||
return newState;
|
||||
return resetState(state);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const resetState = (state: CanvasState) => {
|
||||
const newState = getInitialState();
|
||||
|
||||
// We need to retain the optimal dimension across resets, as it is changed only when the model changes. Copy it
|
||||
// from the old state, then recalculate the bbox size & scaled size.
|
||||
newState.bbox.optimalDimension = state.bbox.optimalDimension;
|
||||
const rect = calculateNewSize(
|
||||
newState.bbox.aspectRatio.value,
|
||||
newState.bbox.optimalDimension * newState.bbox.optimalDimension
|
||||
);
|
||||
newState.bbox.rect.width = rect.width;
|
||||
newState.bbox.rect.height = rect.height;
|
||||
syncScaledSize(newState);
|
||||
|
||||
return newState;
|
||||
};
|
||||
|
||||
export const {
|
||||
canvasMetadataRecalled,
|
||||
canvasUndo,
|
||||
canvasRedo,
|
||||
canvasClearHistory,
|
||||
|
||||
@@ -285,6 +285,12 @@ export const handlers = {
|
||||
itemValidator: validators.lora,
|
||||
renderItemValue: renderLoRAValue,
|
||||
}),
|
||||
|
||||
canvasV2Metadata: buildHandlers({
|
||||
getLabel: () => t('metadata.canvasV2Metadata'),
|
||||
parser: parsers.canvasV2Metadata,
|
||||
recaller: recallers.canvasV2Metadata,
|
||||
}),
|
||||
} as const;
|
||||
|
||||
type ParsedValue = Awaited<ReturnType<(typeof handlers)[keyof typeof handlers]['parse']>>;
|
||||
|
||||
@@ -3,12 +3,13 @@ import { defaultLoRAConfig } from 'features/controlLayers/store/lorasSlice';
|
||||
import type {
|
||||
CanvasControlLayerState,
|
||||
CanvasInpaintMaskState,
|
||||
CanvasMetadata,
|
||||
CanvasRasterLayerState,
|
||||
CanvasReferenceImageState,
|
||||
CanvasRegionalGuidanceState,
|
||||
LoRA,
|
||||
} from 'features/controlLayers/store/types';
|
||||
import { zCanvasRasterLayerState } from 'features/controlLayers/store/types';
|
||||
import { zCanvasMetadata, zCanvasRasterLayerState } from 'features/controlLayers/store/types';
|
||||
import {
|
||||
imageDTOToImageWithDims,
|
||||
initialControlNet,
|
||||
@@ -396,6 +397,11 @@ const parseLayer: MetadataParseFunc<
|
||||
| CanvasInpaintMaskState
|
||||
> = (metadataItem) => zCanvasRasterLayerState.parseAsync(metadataItem);
|
||||
|
||||
const parseCanvasV2Metadata: MetadataParseFunc<CanvasMetadata> = async (metadata) => {
|
||||
const metadataItem = await getProperty(metadata, 'canvas_v2_metadata', undefined);
|
||||
return zCanvasMetadata.parseAsync(metadataItem);
|
||||
};
|
||||
|
||||
const parseLayers: MetadataParseFunc<
|
||||
(
|
||||
| CanvasRasterLayerState
|
||||
@@ -660,4 +666,5 @@ export const parsers = {
|
||||
ipAdapterToIPAdapterLayer: parseIPAdapterToIPAdapterLayer,
|
||||
layer: parseLayer,
|
||||
layers: parseLayers,
|
||||
canvasV2Metadata: parseCanvasV2Metadata,
|
||||
} as const;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getStore } from 'app/store/nanostores/store';
|
||||
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,
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
t5EncoderModelSelected,
|
||||
vaeSelected,
|
||||
} from 'features/controlLayers/store/paramsSlice';
|
||||
import type { LoRA } from 'features/controlLayers/store/types';
|
||||
import type { CanvasMetadata, LoRA } from 'features/controlLayers/store/types';
|
||||
import { setHrfEnabled, setHrfMethod, setHrfStrength } from 'features/hrf/store/hrfSlice';
|
||||
import type { MetadataRecallFunc } from 'features/metadata/types';
|
||||
import { modelSelected } from 'features/parameters/store/actions';
|
||||
@@ -175,6 +175,22 @@ const recallAllLoRAs: MetadataRecallFunc<LoRA[]> = (loras) => {
|
||||
});
|
||||
};
|
||||
|
||||
const recallCanvasV2Metadata: MetadataRecallFunc<CanvasMetadata> = (canvasMetadata) => {
|
||||
if (
|
||||
canvasMetadata.controlLayers.length === 0 &&
|
||||
canvasMetadata.rasterLayers.length === 0 &&
|
||||
canvasMetadata.inpaintMasks.length === 0 &&
|
||||
canvasMetadata.referenceImages.length === 0 &&
|
||||
canvasMetadata.regionalGuidance.length === 0
|
||||
) {
|
||||
// Nothing to recall
|
||||
return;
|
||||
}
|
||||
|
||||
const { dispatch } = getStore();
|
||||
dispatch(canvasMetadataRecalled(canvasMetadata));
|
||||
};
|
||||
|
||||
export const recallers = {
|
||||
positivePrompt: recallPositivePrompt,
|
||||
negativePrompt: recallNegativePrompt,
|
||||
@@ -203,4 +219,5 @@ export const recallers = {
|
||||
lora: recallLoRA,
|
||||
loras: recallAllLoRAs,
|
||||
t5EncoderModel: recallT5Encoder,
|
||||
canvasV2Metadata: recallCanvasV2Metadata,
|
||||
} as const;
|
||||
|
||||
Reference in New Issue
Block a user