diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/userInvokedCanvas.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/userInvokedCanvas.ts index 2ef62aed7b..17b2eeed46 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/userInvokedCanvas.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/userInvokedCanvas.ts @@ -40,7 +40,7 @@ export const addUserInvokedCanvasListener = () => { const state = getState(); // Build canvas blobs - const canvasBlobsAndImageData = await getCanvasData(state); + const canvasBlobsAndImageData = await getCanvasData(state.canvas); if (!canvasBlobsAndImageData) { log.error('Unable to create canvas data'); diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx index 69bf628a39..8c1dfbb86f 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasStatusText.tsx @@ -2,8 +2,8 @@ import { Box, Flex } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { useAppSelector } from 'app/store/storeHooks'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; +import GenerationModeStatusText from 'features/parameters/components/Parameters/Canvas/GenerationModeStatusText'; import { isEqual } from 'lodash-es'; - import { useTranslation } from 'react-i18next'; import roundToHundreth from '../util/roundToHundreth'; import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos'; @@ -110,6 +110,7 @@ const IAICanvasStatusText = () => { }, }} > + { }} > - ) => { + state.generationMode = action.payload; + }, }, extraReducers: (builder) => { builder.addCase(sessionCanceled.pending, (state) => { @@ -955,6 +959,7 @@ export const { stagingAreaInitialized, canvasSessionIdChanged, setShouldAntialias, + generationModeChanged, } = canvasSlice.actions; export default canvasSlice.reducer; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts index 48d59395ab..ba85a7e132 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasTypes.ts @@ -168,4 +168,7 @@ export interface CanvasState { stageDimensions: Dimensions; stageScale: number; tool: CanvasTool; + generationMode?: GenerationMode; } + +export type GenerationMode = 'txt2img' | 'img2img' | 'inpaint' | 'outpaint'; diff --git a/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts b/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts index d37ee7b8d0..855420f78a 100644 --- a/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts +++ b/invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts @@ -1,6 +1,5 @@ import { logger } from 'app/logging/logger'; -import { RootState } from 'app/store/store'; -import { isCanvasMaskLine } from '../store/canvasTypes'; +import { CanvasState, isCanvasMaskLine } from '../store/canvasTypes'; import createMaskStage from './createMaskStage'; import { getCanvasBaseLayer, getCanvasStage } from './konvaInstanceProvider'; import { konvaNodeToBlob } from './konvaNodeToBlob'; @@ -9,7 +8,7 @@ import { konvaNodeToImageData } from './konvaNodeToImageData'; /** * Gets Blob and ImageData objects for the base and mask layers */ -export const getCanvasData = async (state: RootState) => { +export const getCanvasData = async (canvasState: CanvasState) => { const log = logger('canvas'); const canvasBaseLayer = getCanvasBaseLayer(); @@ -26,7 +25,7 @@ export const getCanvasData = async (state: RootState) => { boundingBoxDimensions, isMaskEnabled, shouldPreserveMaskedArea, - } = state.canvas; + } = canvasState; const boundingBox = { ...boundingBoxCoordinates, diff --git a/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts b/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts index 5b38ecf938..d3e8792690 100644 --- a/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts +++ b/invokeai/frontend/web/src/features/canvas/util/getCanvasGenerationMode.ts @@ -2,11 +2,12 @@ import { areAnyPixelsBlack, getImageDataTransparency, } from 'common/util/arrayBuffer'; +import { GenerationMode } from '../store/canvasTypes'; export const getCanvasGenerationMode = ( baseImageData: ImageData, maskImageData: ImageData -) => { +): GenerationMode => { const { isPartiallyTransparent: baseIsPartiallyTransparent, isFullyTransparent: baseIsFullyTransparent, diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/GenerationModeStatusText.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/GenerationModeStatusText.tsx new file mode 100644 index 0000000000..5c6bbd0ba3 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/GenerationModeStatusText.tsx @@ -0,0 +1,55 @@ +import { Box } from '@chakra-ui/react'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { generationModeChanged } from 'features/canvas/store/canvasSlice'; +import { getCanvasData } from 'features/canvas/util/getCanvasData'; +import { getCanvasGenerationMode } from 'features/canvas/util/getCanvasGenerationMode'; +import { useDebounce } from 'react-use'; + +const GENERATION_MODE_NAME_MAP = { + txt2img: 'Text to Image', + img2img: 'Image to Image', + inpaint: 'Inpaint', + outpaint: 'Inpaint', +}; + +export const useGenerationMode = () => { + const dispatch = useAppDispatch(); + const canvasState = useAppSelector((state) => state.canvas); + + useDebounce( + async () => { + // Build canvas blobs + const canvasBlobsAndImageData = await getCanvasData(canvasState); + + if (!canvasBlobsAndImageData) { + return; + } + + const { baseImageData, maskImageData } = canvasBlobsAndImageData; + + // Determine the generation mode + const generationMode = getCanvasGenerationMode( + baseImageData, + maskImageData + ); + + dispatch(generationModeChanged(generationMode)); + }, + 1000, + [dispatch, canvasState, generationModeChanged] + ); +}; + +const GenerationModeStatusText = () => { + const generationMode = useAppSelector((state) => state.canvas.generationMode); + + useGenerationMode(); + + return ( + + Mode: {generationMode ? GENERATION_MODE_NAME_MAP[generationMode] : '...'} + + ); +}; + +export default GenerationModeStatusText;