Skip to content

feat(ui): display canvas generation mode in status text #3915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,22 @@ export const addUserInvokedCanvasListener = () => {

const state = getState();

const {
layerState,
boundingBoxCoordinates,
boundingBoxDimensions,
isMaskEnabled,
shouldPreserveMaskedArea,
} = state.canvas;

// Build canvas blobs
const canvasBlobsAndImageData = await getCanvasData(state);
const canvasBlobsAndImageData = await getCanvasData(
layerState,
boundingBoxCoordinates,
boundingBoxDimensions,
isMaskEnabled,
shouldPreserveMaskedArea
);

if (!canvasBlobsAndImageData) {
log.error('Unable to create canvas data');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -110,6 +110,7 @@ const IAICanvasStatusText = () => {
},
}}
>
<GenerationModeStatusText />
<Box
style={{
color: activeLayerColor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ import { Box, ButtonGroup, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import IAIMantineSelect from 'common/components/IAIMantineSelect';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
import { useSingleAndDoubleClick } from 'common/hooks/useSingleAndDoubleClick';
import {
canvasCopiedToClipboard,
canvasDownloadedAsImage,
canvasMerged,
canvasSavedToGallery,
} from 'features/canvas/store/actions';
import {
canvasSelector,
isStagingSelector,
Expand All @@ -21,16 +29,8 @@ import {
} from 'features/canvas/store/canvasTypes';
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
import { systemSelector } from 'features/system/store/systemSelectors';
import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboard';
import { isEqual } from 'lodash-es';

import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
import {
canvasCopiedToClipboard,
canvasDownloadedAsImage,
canvasMerged,
canvasSavedToGallery,
} from 'features/canvas/store/actions';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import {
Expand All @@ -48,7 +48,6 @@ import IAICanvasRedoButton from './IAICanvasRedoButton';
import IAICanvasSettingsButtonPopover from './IAICanvasSettingsButtonPopover';
import IAICanvasToolChooserOptions from './IAICanvasToolChooserOptions';
import IAICanvasUndoButton from './IAICanvasUndoButton';
import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboard';

export const selector = createSelector(
[systemSelector, canvasSelector, isStagingSelector],
Expand Down Expand Up @@ -220,7 +219,7 @@ const IAICanvasToolbar = () => {
}}
>
<Box w={24}>
<IAIMantineSearchableSelect
<IAIMantineSelect
tooltip={`${t('unifiedCanvas.layer')} (Q)`}
value={layer}
data={LAYER_NAMES_DICT}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useAppSelector } from 'app/store/storeHooks';
import { GenerationMode } from 'features/canvas/store/canvasTypes';
import { getCanvasData } from 'features/canvas/util/getCanvasData';
import { getCanvasGenerationMode } from 'features/canvas/util/getCanvasGenerationMode';
import { useEffect, useState } from 'react';
import { useDebounce } from 'react-use';

export const useCanvasGenerationMode = () => {
const layerState = useAppSelector((state) => state.canvas.layerState);

const boundingBoxCoordinates = useAppSelector(
(state) => state.canvas.boundingBoxCoordinates
);
const boundingBoxDimensions = useAppSelector(
(state) => state.canvas.boundingBoxDimensions
);
const isMaskEnabled = useAppSelector((state) => state.canvas.isMaskEnabled);

const shouldPreserveMaskedArea = useAppSelector(
(state) => state.canvas.shouldPreserveMaskedArea
);
const [generationMode, setGenerationMode] = useState<
GenerationMode | undefined
>();

useEffect(() => {
setGenerationMode(undefined);
}, [
layerState,
boundingBoxCoordinates,
boundingBoxDimensions,
isMaskEnabled,
shouldPreserveMaskedArea,
]);

useDebounce(
async () => {
// Build canvas blobs
const canvasBlobsAndImageData = await getCanvasData(
layerState,
boundingBoxCoordinates,
boundingBoxDimensions,
isMaskEnabled,
shouldPreserveMaskedArea
);

if (!canvasBlobsAndImageData) {
return;
}

const { baseImageData, maskImageData } = canvasBlobsAndImageData;

// Determine the generation mode
const generationMode = getCanvasGenerationMode(
baseImageData,
maskImageData
);

setGenerationMode(generationMode);
},
1000,
[
layerState,
boundingBoxCoordinates,
boundingBoxDimensions,
isMaskEnabled,
shouldPreserveMaskedArea,
]
);

return generationMode;
};
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,7 @@ export interface CanvasState {
stageDimensions: Dimensions;
stageScale: number;
tool: CanvasTool;
generationMode?: GenerationMode;
}

export type GenerationMode = 'txt2img' | 'img2img' | 'inpaint' | 'outpaint';
26 changes: 14 additions & 12 deletions invokeai/frontend/web/src/features/canvas/util/getCanvasData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { logger } from 'app/logging/logger';
import { RootState } from 'app/store/store';
import { isCanvasMaskLine } from '../store/canvasTypes';
import { Vector2d } from 'konva/lib/types';
import {
CanvasLayerState,
Dimensions,
isCanvasMaskLine,
} from '../store/canvasTypes';
import createMaskStage from './createMaskStage';
import { getCanvasBaseLayer, getCanvasStage } from './konvaInstanceProvider';
import { konvaNodeToBlob } from './konvaNodeToBlob';
Expand All @@ -9,7 +13,13 @@ 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 (
layerState: CanvasLayerState,
boundingBoxCoordinates: Vector2d,
boundingBoxDimensions: Dimensions,
isMaskEnabled: boolean,
shouldPreserveMaskedArea: boolean
) => {
const log = logger('canvas');

const canvasBaseLayer = getCanvasBaseLayer();
Expand All @@ -20,14 +30,6 @@ export const getCanvasData = async (state: RootState) => {
return;
}

const {
layerState: { objects },
boundingBoxCoordinates,
boundingBoxDimensions,
isMaskEnabled,
shouldPreserveMaskedArea,
} = state.canvas;

const boundingBox = {
...boundingBoxCoordinates,
...boundingBoxDimensions,
Expand Down Expand Up @@ -58,7 +60,7 @@ export const getCanvasData = async (state: RootState) => {

// For the mask layer, use the normal boundingBox
const maskStage = await createMaskStage(
isMaskEnabled ? objects.filter(isCanvasMaskLine) : [], // only include mask lines, and only if mask is enabled
isMaskEnabled ? layerState.objects.filter(isCanvasMaskLine) : [], // only include mask lines, and only if mask is enabled
boundingBox,
shouldPreserveMaskedArea
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Box } from '@chakra-ui/react';
import { useCanvasGenerationMode } from 'features/canvas/hooks/useCanvasGenerationMode';

const GENERATION_MODE_NAME_MAP = {
txt2img: 'Text to Image',
img2img: 'Image to Image',
inpaint: 'Inpaint',
outpaint: 'Inpaint',
};

const GenerationModeStatusText = () => {
const generationMode = useCanvasGenerationMode();

return (
<Box>
Mode: {generationMode ? GENERATION_MODE_NAME_MAP[generationMode] : '...'}
</Box>
);
};

export default GenerationModeStatusText;