From f61af188f94bb5a57a53591d5b1e489e8ac83b8d Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:00:19 +1000 Subject: [PATCH] tidy(ui): remove unused code, initial image --- .../middleware/listenerMiddleware/index.ts | 2 - .../listeners/canvasSessionRequested.ts | 29 -- .../components/CanvasEntityList.tsx | 7 +- .../components/ControlLayersToolbar.tsx | 4 +- .../components/InitialImage/InitialImage.tsx | 25 -- .../InitialImage/InitialImageActionsMenu.tsx | 0 .../InitialImage/InitialImageHeader.tsx | 34 -- .../InitialImage/InitialImagePreview.tsx | 100 ------ .../InitialImage/InitialImageSettings.tsx | 13 - .../components/NewSessionButton.tsx | 15 - .../controlLayers/konva/CanvasInitialImage.ts | 65 ---- .../controlLayers/konva/CanvasManager.ts | 47 +-- .../controlLayers/konva/CanvasRegion.ts | 292 ------------------ .../controlLayers/konva/CanvasStateApi.ts | 3 - .../controlLayers/konva/entityBbox.ts | 250 --------------- .../controlLayers/store/canvasV2Slice.ts | 18 -- .../store/initialImageReducers.ts | 38 --- .../controlLayers/store/sessionReducers.ts | 4 - .../src/features/controlLayers/store/types.ts | 24 +- 19 files changed, 10 insertions(+), 960 deletions(-) delete mode 100644 invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSessionRequested.ts delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImage.tsx delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageActionsMenu.tsx delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageHeader.tsx delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImagePreview.tsx delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageSettings.tsx delete mode 100644 invokeai/frontend/web/src/features/controlLayers/components/NewSessionButton.tsx delete mode 100644 invokeai/frontend/web/src/features/controlLayers/konva/CanvasInitialImage.ts delete mode 100644 invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts delete mode 100644 invokeai/frontend/web/src/features/controlLayers/konva/entityBbox.ts delete mode 100644 invokeai/frontend/web/src/features/controlLayers/store/initialImageReducers.ts diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts index 79b90776b8..29df0bf542 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts @@ -9,7 +9,6 @@ import { addBatchEnqueuedListener } from 'app/store/middleware/listenerMiddlewar import { addDeleteBoardAndImagesFulfilledListener } from 'app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted'; import { addBoardIdSelectedListener } from 'app/store/middleware/listenerMiddleware/listeners/boardIdSelected'; import { addBulkDownloadListeners } from 'app/store/middleware/listenerMiddleware/listeners/bulkDownload'; -import { addCanvasSessionRequestedListener } from 'app/store/middleware/listenerMiddleware/listeners/canvasSessionRequested'; import { addControlAdapterPreprocessor } from 'app/store/middleware/listenerMiddleware/listeners/controlAdapterPreprocessor'; import { addEnqueueRequestedLinear } from 'app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear'; import { addEnqueueRequestedNodes } from 'app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes'; @@ -90,7 +89,6 @@ addBatchEnqueuedListener(startAppListening); // addStagingAreaImageSavedListener(startAppListening); // addCommitStagingAreaImageListener(startAppListening); addStagingListeners(startAppListening); -addCanvasSessionRequestedListener(startAppListening); // Socket.IO addGeneratorProgressEventListener(startAppListening); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSessionRequested.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSessionRequested.ts deleted file mode 100644 index 0e1c92dcff..0000000000 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/canvasSessionRequested.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; -import { - layerAdded, - layerImageAdded, - sessionRequested, - sessionStarted, -} from 'features/controlLayers/store/canvasV2Slice'; -import { getImageDTO } from 'services/api/endpoints/images'; -import { assert } from 'tsafe'; - -export const addCanvasSessionRequestedListener = (startAppListening: AppStartListening) => { - startAppListening({ - actionCreator: sessionRequested, - effect: async (action, { getState, dispatch }) => { - const initialImageObject = getState().canvasV2.initialImage.imageObject; - if (initialImageObject) { - // We have an initial image that needs to be converted to a layer - dispatch(layerAdded()); - const newLayer = getState().canvasV2.layers.entities[0]; - assert(newLayer, 'Expected new layer to be created'); - const imageDTO = await getImageDTO(initialImageObject.image.name); - assert(imageDTO, 'Unable to fetch initial image DTO'); - dispatch(layerImageAdded({ id: newLayer.id, imageDTO })); - } - - dispatch(sessionStarted()); - }, - }); -}; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx index d9d0255d14..e76b6ab3ed 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasEntityList.tsx @@ -1,9 +1,7 @@ /* eslint-disable i18next/no-literal-string */ import { Flex } from '@invoke-ai/ui-library'; -import { useAppSelector } from 'app/store/storeHooks'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; import { CAEntityList } from 'features/controlLayers/components/ControlAdapter/CAEntityList'; -import { InitialImage } from 'features/controlLayers/components/InitialImage/InitialImage'; import { IM } from 'features/controlLayers/components/InpaintMask/IM'; import { IPAEntityList } from 'features/controlLayers/components/IPAdapter/IPAEntityList'; import { LayerEntityList } from 'features/controlLayers/components/Layer/LayerEntityList'; @@ -11,17 +9,14 @@ import { RGEntityList } from 'features/controlLayers/components/RegionalGuidance import { memo } from 'react'; export const CanvasEntityList = memo(() => { - const isCanvasSessionActive = useAppSelector((s) => s.canvasV2.session.isActive); - return ( - {isCanvasSessionActive && } + - {!isCanvasSessionActive && } ); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersToolbar.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersToolbar.tsx index 05a7ae638f..1b8d52585e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersToolbar.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ControlLayersToolbar.tsx @@ -7,7 +7,6 @@ import { BrushWidth } from 'features/controlLayers/components/BrushWidth'; import ControlLayersSettingsPopover from 'features/controlLayers/components/ControlLayersSettingsPopover'; import { EraserWidth } from 'features/controlLayers/components/EraserWidth'; import { FillColorPicker } from 'features/controlLayers/components/FillColorPicker'; -import { NewSessionButton } from 'features/controlLayers/components/NewSessionButton'; import { ResetCanvasButton } from 'features/controlLayers/components/ResetCanvasButton'; import { ToolChooser } from 'features/controlLayers/components/ToolChooser'; import { UndoRedoButtonGroup } from 'features/controlLayers/components/UndoRedoButtonGroup'; @@ -25,7 +24,7 @@ export const ControlLayersToolbar = memo(() => { return; } for (const l of canvasManager.layers.values()) { - l.calculateBbox(); + l.transformer.requestRectCalculation(); } }, [canvasManager]); const onChangeDebugging = useCallback( @@ -61,7 +60,6 @@ export const ControlLayersToolbar = memo(() => { - diff --git a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImage.tsx b/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImage.tsx deleted file mode 100644 index 00fdc673c0..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImage.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useDisclosure } from '@invoke-ai/ui-library'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { CanvasEntityContainer } from 'features/controlLayers/components/common/CanvasEntityContainer'; -import { InitialImageHeader } from 'features/controlLayers/components/InitialImage/InitialImageHeader'; -import { InitialImageSettings } from 'features/controlLayers/components/InitialImage/InitialImageSettings'; -import { entitySelected } from 'features/controlLayers/store/canvasV2Slice'; -import { memo, useCallback } from 'react'; - -export const InitialImage = memo(() => { - const dispatch = useAppDispatch(); - const isSelected = useAppSelector((s) => s.canvasV2.selectedEntityIdentifier?.id === 'initial_image'); - const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true }); - const onSelect = useCallback(() => { - dispatch(entitySelected({ id: 'initial_image', type: 'initial_image' })); - }, [dispatch]); - - return ( - - - {isOpen && } - - ); -}); - -InitialImage.displayName = 'InitialImage'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageActionsMenu.tsx b/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageActionsMenu.tsx deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageHeader.tsx b/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageHeader.tsx deleted file mode 100644 index 8af3e98f40..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageHeader.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Spacer } from '@invoke-ai/ui-library'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { CanvasEntityEnabledToggle } from 'features/controlLayers/components/common/CanvasEntityEnabledToggle'; -import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader'; -import { CanvasEntityTitle } from 'features/controlLayers/components/common/CanvasEntityTitle'; -import { iiIsEnabledToggled } from 'features/controlLayers/store/canvasV2Slice'; -import { memo, useCallback, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; - -type Props = { - onToggleVisibility: () => void; -}; - -export const InitialImageHeader = memo(({ onToggleVisibility }: Props) => { - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const isEnabled = useAppSelector((s) => s.canvasV2.initialImage.isEnabled); - const onToggleIsEnabled = useCallback(() => { - dispatch(iiIsEnabledToggled()); - }, [dispatch]); - const title = useMemo(() => { - return `${t('controlLayers.initialImage')}`; - }, [t]); - - return ( - - - - - - ); -}); - -InitialImageHeader.displayName = 'InitialImageHeader'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImagePreview.tsx b/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImagePreview.tsx deleted file mode 100644 index dca1a155fa..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImagePreview.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { Flex, useShiftModifier } from '@invoke-ai/ui-library'; -import { skipToken } from '@reduxjs/toolkit/query'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import IAIDndImage from 'common/components/IAIDndImage'; -import IAIDndImageIcon from 'common/components/IAIDndImageIcon'; -import { bboxHeightChanged, bboxWidthChanged, iiReset } from 'features/controlLayers/store/canvasV2Slice'; -import { selectOptimalDimension } from 'features/controlLayers/store/selectors'; -import type { ImageDraggableData, InitialImageDropData } from 'features/dnd/types'; -import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize'; -import { memo, useCallback, useEffect, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { PiArrowCounterClockwiseBold, PiRulerBold } from 'react-icons/pi'; -import { useGetImageDTOQuery } from 'services/api/endpoints/images'; - -export const InitialImagePreview = memo(() => { - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const initialImage = useAppSelector((s) => s.canvasV2.initialImage); - const isConnected = useAppSelector((s) => s.system.isConnected); - const optimalDimension = useAppSelector(selectOptimalDimension); - const shift = useShiftModifier(); - - const { currentData: imageDTO, isError: isErrorControlImage } = useGetImageDTOQuery( - initialImage.imageObject?.image.name ?? skipToken - ); - - const onReset = useCallback(() => { - dispatch(iiReset()); - }, [dispatch]); - - const onUseSize = useCallback(() => { - if (!imageDTO) { - return; - } - - const options = { updateAspectRatio: true, clamp: true }; - if (shift) { - const { width, height } = imageDTO; - dispatch(bboxWidthChanged({ width, ...options })); - dispatch(bboxHeightChanged({ height, ...options })); - } else { - const { width, height } = calculateNewSize(imageDTO.width / imageDTO.height, optimalDimension * optimalDimension); - dispatch(bboxWidthChanged({ width, ...options })); - dispatch(bboxHeightChanged({ height, ...options })); - } - }, [imageDTO, dispatch, optimalDimension, shift]); - - const draggableData = useMemo(() => { - if (imageDTO) { - return { - id: 'initial_image', - payloadType: 'IMAGE_DTO', - payload: { imageDTO }, - }; - } - }, [imageDTO]); - - const droppableData = useMemo( - () => ({ id: 'initial_image', actionType: 'SET_INITIAL_IMAGE' }), - [] - ); - - useEffect(() => { - if (isConnected && isErrorControlImage) { - onReset(); - } - }, [onReset, isConnected, isErrorControlImage]); - - return ( - - - - - {imageDTO && ( - - } - tooltip={t('controlnet.resetControlImage')} - /> - } - tooltip={ - shift ? t('controlnet.setControlImageDimensionsForce') : t('controlnet.setControlImageDimensions') - } - /> - - )} - - - ); -}); - -InitialImagePreview.displayName = 'InitialImagePreview'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageSettings.tsx b/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageSettings.tsx deleted file mode 100644 index 9c9da2f536..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/InitialImage/InitialImageSettings.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { CanvasEntitySettings } from 'features/controlLayers/components/common/CanvasEntitySettings'; -import { InitialImagePreview } from 'features/controlLayers/components/InitialImage/InitialImagePreview'; -import { memo } from 'react'; - -export const InitialImageSettings = memo(() => { - return ( - - - - ); -}); - -InitialImageSettings.displayName = 'InitialImageSettings'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/NewSessionButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/NewSessionButton.tsx deleted file mode 100644 index a04ce3089b..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/NewSessionButton.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Button } from '@invoke-ai/ui-library'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { sessionRequested } from 'features/controlLayers/store/canvasV2Slice'; -import { memo, useCallback } from 'react'; - -export const NewSessionButton = memo(() => { - const dispatch = useAppDispatch(); - const onClick = useCallback(() => { - dispatch(sessionRequested()); - }, [dispatch]); - - return ; -}); - -NewSessionButton.displayName = 'NewSessionButton'; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasInitialImage.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasInitialImage.ts deleted file mode 100644 index 52bb4a398a..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasInitialImage.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { CanvasImageRenderer } from 'features/controlLayers/konva/CanvasImage'; -import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; -import type { InitialImageEntity } from 'features/controlLayers/store/types'; -import Konva from 'konva'; - -export class CanvasInitialImage { - static NAME_PREFIX = 'initial-image'; - static LAYER_NAME = `${CanvasInitialImage.NAME_PREFIX}_layer`; - static GROUP_NAME = `${CanvasInitialImage.NAME_PREFIX}_group`; - static OBJECT_GROUP_NAME = `${CanvasInitialImage.NAME_PREFIX}_object-group`; - - private state: InitialImageEntity; - - id = 'initial_image'; - manager: CanvasManager; - - konva: { - layer: Konva.Layer; - group: Konva.Group; - objectGroup: Konva.Group; - }; - - image: CanvasImageRenderer | null; - - constructor(state: InitialImageEntity, manager: CanvasManager) { - this.manager = manager; - this.konva = { - layer: new Konva.Layer({ name: CanvasInitialImage.LAYER_NAME, imageSmoothingEnabled: true, listening: false }), - group: new Konva.Group({ name: CanvasInitialImage.GROUP_NAME, listening: false }), - objectGroup: new Konva.Group({ name: CanvasInitialImage.OBJECT_GROUP_NAME, listening: false }), - }; - this.konva.group.add(this.konva.objectGroup); - this.konva.layer.add(this.konva.group); - - this.image = null; - this.state = state; - } - - async render(state: InitialImageEntity) { - this.state = state; - - if (!this.state.imageObject) { - this.konva.layer.visible(false); - return; - } - - if (!this.image) { - this.image = new CanvasImageRenderer(this.state.imageObject); - this.konva.objectGroup.add(this.image.konva.group); - await this.image.update(this.state.imageObject, true); - } else if (!this.image.isLoading && !this.image.isError) { - await this.image.update(this.state.imageObject); - } - - if (this.state && this.state.isEnabled && !this.image?.isLoading && !this.image?.isError) { - this.konva.layer.visible(true); - } else { - this.konva.layer.visible(false); - } - } - - destroy(): void { - this.konva.layer.destroy(); - } -} diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts index 6cac07952c..d16f7997e7 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts @@ -6,7 +6,6 @@ import { PubSub } from 'common/util/PubSub/PubSub'; import type { CanvasBrushLineRenderer } from 'features/controlLayers/konva/CanvasBrushLine'; import type { CanvasEraserLineRenderer } from 'features/controlLayers/konva/CanvasEraserLine'; import type { CanvasImageRenderer } from 'features/controlLayers/konva/CanvasImage'; -import { CanvasInitialImage } from 'features/controlLayers/konva/CanvasInitialImage'; import { CanvasObjectRenderer } from 'features/controlLayers/konva/CanvasObjectRenderer'; import { CanvasProgressPreview } from 'features/controlLayers/konva/CanvasProgressPreview'; import type { CanvasRectRenderer } from 'features/controlLayers/konva/CanvasRect'; @@ -15,7 +14,6 @@ import { getCompositeLayerImage, getControlAdapterImage, getGenerationMode, - getInitialImage, getInpaintMaskImage, getPrefixedId, getRegionMaskImage, @@ -48,7 +46,6 @@ import { CanvasControlAdapter } from './CanvasControlAdapter'; import { CanvasLayerAdapter } from './CanvasLayerAdapter'; import { CanvasMaskAdapter } from './CanvasMaskAdapter'; import { CanvasPreview } from './CanvasPreview'; -import type { CanvasRegion } from './CanvasRegion'; import { CanvasStagingArea } from './CanvasStagingArea'; import { CanvasStateApi } from './CanvasStateApi'; import { CanvasTool } from './CanvasTool'; @@ -120,7 +117,6 @@ export class CanvasManager { layers: Map; regions: Map; inpaintMask: CanvasMaskAdapter; - initialImage: CanvasInitialImage; util: Util; stateApi: CanvasStateApi; preview: CanvasPreview; @@ -188,9 +184,6 @@ export class CanvasManager { this.regions = new Map(); this.controlAdapters = new Map(); - this.initialImage = new CanvasInitialImage(this.stateApi.getInitialImageState(), this); - this.stage.add(this.initialImage.konva.layer); - this._worker.onmessage = (event: MessageEvent) => { const { type, data } = event.data; if (type === 'log') { @@ -250,10 +243,6 @@ export class CanvasManager { this._worker.postMessage(task, [data.buffer]); } - async renderInitialImage() { - await this.initialImage.render(this.stateApi.getInitialImageState()); - } - async renderProgressPreview() { await this.preview.progressPreview.render(this.stateApi.$lastProgressEvent.get()); } @@ -286,7 +275,6 @@ export class CanvasManager { const regions = getRegionsState().entities; let zIndex = 0; this.background.konva.layer.zIndex(++zIndex); - this.initialImage.konva.layer.zIndex(++zIndex); for (const layer of layers) { this.layers.get(layer.id)?.konva.layer.zIndex(++zIndex); } @@ -322,7 +310,7 @@ export class CanvasManager { | CanvasRegionalGuidanceState | CanvasInpaintMaskState | null = null; - let entityAdapter: CanvasLayerAdapter | CanvasControlAdapter | CanvasRegion | CanvasMaskAdapter | null = null; + let entityAdapter: CanvasLayerAdapter | CanvasControlAdapter | CanvasMaskAdapter | null = null; if (identifier.type === 'layer') { entityState = state.layers.entities.find((i) => i.id === identifier.id) ?? null; @@ -470,17 +458,6 @@ export class CanvasManager { } } - if ( - this._isFirstRender || - state.initialImage !== this._prevState.initialImage || - state.bbox.rect !== this._prevState.bbox.rect || - state.tool.selected !== this._prevState.tool.selected || - state.selectedEntityIdentifier?.id !== this._prevState.selectedEntityIdentifier?.id - ) { - this.log.debug('Rendering initial image'); - await this.renderInitialImage(); - } - if ( this._isFirstRender || state.regions.entities !== this._prevState.regions.entities || @@ -546,8 +523,7 @@ export class CanvasManager { if ( this._isFirstRender || state.bbox !== this._prevState.bbox || - state.tool.selected !== this._prevState.tool.selected || - state.session.isActive !== this._prevState.session.isActive + state.tool.selected !== this._prevState.tool.selected ) { this.log.debug('Rendering generation bbox'); await this.preview.bbox.render(); @@ -656,18 +632,7 @@ export class CanvasManager { } getGenerationMode(): GenerationMode { - const session = this.stateApi.getSession(); - if (session.isActive) { - return getGenerationMode({ manager: this }); - } - - const initialImageState = this.stateApi.getInitialImageState(); - - if (initialImageState.imageObject && initialImageState.isEnabled) { - return 'img2img'; - } - - return 'txt2img'; + return getGenerationMode({ manager: this }); } getControlAdapterImage(arg: Omit[0], 'manager'>) { @@ -683,11 +648,7 @@ export class CanvasManager { } getInitialImage(arg: Omit[0], 'manager'>) { - if (this.stateApi.getSession().isActive) { - return getCompositeLayerImage({ ...arg, manager: this }); - } else { - return getInitialImage({ ...arg, manager: this }); - } + return getCompositeLayerImage({ ...arg, manager: this }); } getLoggingContext() { diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts deleted file mode 100644 index 74a0cdd6de..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasRegion.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { rgbColorToString } from 'common/util/colorCodeTransformers'; -import { CanvasBrushLineRenderer } from 'features/controlLayers/konva/CanvasBrushLine'; -import { CanvasEraserLineRenderer } from 'features/controlLayers/konva/CanvasEraserLine'; -import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; -import { CanvasRectRenderer } from 'features/controlLayers/konva/CanvasRect'; -import { getNodeBboxFast } from 'features/controlLayers/konva/entityBbox'; -import { mapId } from 'features/controlLayers/konva/util'; -import type { - CanvasBrushLineState, - CanvasEraserLineState, - CanvasRectState, - CanvasRegionalGuidanceState, -} from 'features/controlLayers/store/types'; -import { isDrawingTool, RGBA_RED } from 'features/controlLayers/store/types'; -import Konva from 'konva'; -import { assert } from 'tsafe'; - -export class CanvasRegion { - static NAME_PREFIX = 'region'; - static LAYER_NAME = `${CanvasRegion.NAME_PREFIX}_layer`; - static TRANSFORMER_NAME = `${CanvasRegion.NAME_PREFIX}_transformer`; - static GROUP_NAME = `${CanvasRegion.NAME_PREFIX}_group`; - static OBJECT_GROUP_NAME = `${CanvasRegion.NAME_PREFIX}_object-group`; - static COMPOSITING_RECT_NAME = `${CanvasRegion.NAME_PREFIX}_compositing-rect`; - static TYPE = 'regional_guidance' as const; - - private drawingBuffer: CanvasBrushLineState | CanvasEraserLineState | CanvasRectState | null; - private state: CanvasRegionalGuidanceState; - - id: string; - type = CanvasRegion.TYPE; - manager: CanvasManager; - - konva: { - layer: Konva.Layer; - group: Konva.Group; - objectGroup: Konva.Group; - compositingRect: Konva.Rect; - transformer: Konva.Transformer; - }; - - objects: Map; - - constructor(state: CanvasRegionalGuidanceState, manager: CanvasManager) { - this.id = state.id; - this.manager = manager; - - this.konva = { - layer: new Konva.Layer({ name: CanvasRegion.LAYER_NAME, listening: false }), - group: new Konva.Group({ name: CanvasRegion.GROUP_NAME, listening: false }), - objectGroup: new Konva.Group({ name: CanvasRegion.OBJECT_GROUP_NAME, listening: false }), - transformer: new Konva.Transformer({ - name: CanvasRegion.TRANSFORMER_NAME, - shouldOverdrawWholeArea: true, - draggable: true, - dragDistance: 0, - enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right'], - rotateEnabled: false, - flipEnabled: false, - }), - compositingRect: new Konva.Rect({ name: CanvasRegion.COMPOSITING_RECT_NAME, listening: false }), - }; - this.konva.group.add(this.konva.objectGroup); - this.konva.layer.add(this.konva.group); - this.konva.transformer.on('transformend', () => { - this.manager.stateApi.onScaleChanged( - { - id: this.id, - scale: this.konva.group.scaleX(), - position: { x: this.konva.group.x(), y: this.konva.group.y() }, - }, - 'regional_guidance' - ); - }); - this.konva.transformer.on('dragend', () => { - this.manager.stateApi.setEntityPosition( - { id: this.id, position: { x: this.konva.group.x(), y: this.konva.group.y() } }, - 'regional_guidance' - ); - }); - this.konva.layer.add(this.konva.transformer); - this.konva.group.add(this.konva.compositingRect); - this.objects = new Map(); - this.drawingBuffer = null; - this.state = state; - } - - destroy(): void { - this.konva.layer.destroy(); - } - - getDrawingBuffer() { - return this.drawingBuffer; - } - - async setDrawingBuffer(obj: CanvasBrushLineState | CanvasEraserLineState | CanvasRectState | null) { - this.drawingBuffer = obj; - if (this.drawingBuffer) { - if (this.drawingBuffer.type === 'brush_line') { - this.drawingBuffer.color = RGBA_RED; - } else if (this.drawingBuffer.type === 'rect') { - this.drawingBuffer.color = RGBA_RED; - } - - await this.renderObject(this.drawingBuffer, true); - this.updateGroup(true); - } - } - - finalizeDrawingBuffer() { - if (!this.drawingBuffer) { - return; - } - if (this.drawingBuffer.type === 'brush_line') { - this.manager.stateApi.addBrushLine({ id: this.id, brushLine: this.drawingBuffer }, 'regional_guidance'); - } else if (this.drawingBuffer.type === 'eraser_line') { - this.manager.stateApi.addEraserLine({ id: this.id, eraserLine: this.drawingBuffer }, 'regional_guidance'); - } else if (this.drawingBuffer.type === 'rect') { - this.manager.stateApi.addRect({ id: this.id, rect: this.drawingBuffer }, 'regional_guidance'); - } - this.setDrawingBuffer(null); - } - - async render(state: CanvasRegionalGuidanceState) { - this.state = state; - - // Update the layer's position and listening state - this.konva.group.setAttrs({ - x: state.position.x, - y: state.position.y, - scaleX: 1, - scaleY: 1, - }); - - let didDraw = false; - - const objectIds = state.objects.map(mapId); - // Destroy any objects that are no longer in state - for (const object of this.objects.values()) { - if (!objectIds.includes(object.id)) { - this.objects.delete(object.id); - object.destroy(); - didDraw = true; - } - } - - for (const obj of state.objects) { - if (await this.renderObject(obj)) { - didDraw = true; - } - } - - if (this.drawingBuffer) { - if (await this.renderObject(this.drawingBuffer)) { - didDraw = true; - } - } - - this.updateGroup(didDraw); - } - - private async renderObject(obj: CanvasRegionalGuidanceState['objects'][number], force = false): Promise { - if (obj.type === 'brush_line') { - let brushLine = this.objects.get(obj.id); - assert(brushLine instanceof CanvasBrushLineRenderer || brushLine === undefined); - - if (!brushLine) { - brushLine = new CanvasBrushLineRenderer(obj); - this.objects.set(brushLine.id, brushLine); - this.konva.objectGroup.add(brushLine.konva.group); - return true; - } else { - if (brushLine.update(obj, force)) { - return true; - } - } - } else if (obj.type === 'eraser_line') { - let eraserLine = this.objects.get(obj.id); - assert(eraserLine instanceof CanvasEraserLineRenderer || eraserLine === undefined); - - if (!eraserLine) { - eraserLine = new CanvasEraserLineRenderer(obj); - this.objects.set(eraserLine.id, eraserLine); - this.konva.objectGroup.add(eraserLine.konva.group); - return true; - } else { - if (eraserLine.update(obj, force)) { - return true; - } - } - } else if (obj.type === 'rect') { - let rect = this.objects.get(obj.id); - assert(rect instanceof CanvasRectRenderer || rect === undefined); - - if (!rect) { - rect = new CanvasRectRenderer(obj); - this.objects.set(rect.id, rect); - this.konva.objectGroup.add(rect.konva.group); - return true; - } else { - if (rect.update(obj, force)) { - return true; - } - } - } - - return false; - } - - updateGroup(didDraw: boolean) { - this.konva.layer.visible(this.state.isEnabled); - - // The user is allowed to reduce mask opacity to 0, but we need the opacity for the compositing rect to work - this.konva.group.opacity(1); - - if (didDraw) { - // Convert the color to a string, stripping the alpha - the object group will handle opacity. - const rgbColor = rgbColorToString(this.state.fill); - const maskOpacity = this.manager.stateApi.getMaskOpacity(); - this.konva.compositingRect.setAttrs({ - // The rect should be the size of the layer - use the fast method if we don't have a pixel-perfect bbox already - ...getNodeBboxFast(this.konva.objectGroup), - fill: rgbColor, - opacity: maskOpacity, - // Draw this rect only where there are non-transparent pixels under it (e.g. the mask shapes) - globalCompositeOperation: 'source-in', - // This rect must always be on top of all other shapes - zIndex: this.objects.size + 1, - }); - } - - const isSelected = this.manager.stateApi.getIsSelected(this.id); - const selectedTool = this.manager.stateApi.getToolState().selected; - - if (this.objects.size === 0) { - // If the layer is totally empty, reset the cache and bail out. - this.konva.layer.listening(false); - this.konva.transformer.nodes([]); - if (this.konva.group.isCached()) { - this.konva.group.clearCache(); - } - return; - } - - if (isSelected && selectedTool === 'move') { - // When the layer is selected and being moved, we should always cache it. - // We should update the cache if we drew to the layer. - if (!this.konva.group.isCached() || didDraw) { - this.konva.group.cache(); - } - // Activate the transformer - this.konva.layer.listening(true); - this.konva.transformer.nodes([this.konva.group]); - this.konva.transformer.forceUpdate(); - return; - } - - if (isSelected && selectedTool !== 'move') { - // If the layer is selected but not using the move tool, we don't want the layer to be listening. - this.konva.layer.listening(false); - // The transformer also does not need to be active. - this.konva.transformer.nodes([]); - if (isDrawingTool(selectedTool)) { - // We are using a drawing tool (brush, eraser, rect). These tools change the layer's rendered appearance, so we - // should never be cached. - if (this.konva.group.isCached()) { - this.konva.group.clearCache(); - } - } else { - // We are using a non-drawing tool (move, view, bbox), so we should cache the layer. - // We should update the cache if we drew to the layer. - if (!this.konva.group.isCached() || didDraw) { - this.konva.group.cache(); - } - } - return; - } - - if (!isSelected) { - // Unselected layers should not be listening - this.konva.layer.listening(false); - // The transformer also does not need to be active. - this.konva.transformer.nodes([]); - // Update the layer's cache if it's not already cached or we drew to it. - if (!this.konva.group.isCached() || didDraw) { - this.konva.group.cache(); - } - - return; - } - } -} diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts index 8f9a664aa1..6d6b236855 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts @@ -188,9 +188,6 @@ export class CanvasStateApi { getInpaintMaskState = () => { return this.getState().inpaintMask; }; - getInitialImageState = () => { - return this.getState().initialImage; - }; getMaskOpacity = () => { return this.getState().settings.maskOpacity; }; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/entityBbox.ts b/invokeai/frontend/web/src/features/controlLayers/konva/entityBbox.ts deleted file mode 100644 index 8e8763460b..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/konva/entityBbox.ts +++ /dev/null @@ -1,250 +0,0 @@ -import openBase64ImageInTab from 'common/util/openBase64ImageInTab'; -import { getLayerBboxId } from 'features/controlLayers/konva/naming'; -import { imageDataToDataURL } from 'features/controlLayers/konva/util'; -import type { - BboxChangedArg, - CanvasControlAdapterState, - CanvasEntityState, - CanvasLayerState, - CanvasRegionalGuidanceState, -} from 'features/controlLayers/store/types'; -import Konva from 'konva'; -import type { IRect } from 'konva/lib/types'; -import { assert } from 'tsafe'; - -/** - * Creates a bounding box rect for a layer. - * @param entity The layer state for the layer to create the bounding box for - * @param konvaLayer The konva layer to attach the bounding box to - */ -export const createBboxRect = (entity: CanvasEntityState, konvaLayer: Konva.Layer): Konva.Rect => { - const rect = new Konva.Rect({ - id: getLayerBboxId(entity.id), - name: 'bbox', - strokeWidth: 1, - visible: false, - }); - konvaLayer.add(rect); - return rect; -}; - -/** - * Logic to create and render bounding boxes for layers. - * Some utils are included for calculating bounding boxes. - */ - -type Extents = { - minX: number; - minY: number; - maxX: number; - maxY: number; -}; - -const GET_CLIENT_RECT_CONFIG = { skipTransform: true }; - -/** - * Get the bounding box of an image. - * @param imageData The ImageData object to get the bounding box of. - * @returns The minimum and maximum x and y values of the image's bounding box, or null if the image has no pixels. - */ -export const getImageDataBbox = (imageData: ImageData): Extents | null => { - const { data, width, height } = imageData; - let minX = width; - let minY = height; - let maxX = -1; - let maxY = -1; - let alpha = 0; - let isEmpty = true; - - for (let y = 0; y < height; y++) { - for (let x = 0; x < width; x++) { - alpha = data[(y * width + x) * 4 + 3] ?? 0; - if (alpha > 0) { - isEmpty = false; - if (x < minX) { - minX = x; - } - if (x > maxX) { - maxX = x; - } - if (y < minY) { - minY = y; - } - if (y > maxY) { - maxY = y; - } - } - } - } - - return isEmpty ? null : { minX, minY, maxX: maxX + 1, maxY: maxY + 1 }; -}; - -/** - * Clones a regional guidance konva layer onto an offscreen stage/canvas. This allows the pixel data for a given layer - * to be captured, manipulated or analyzed without interference from other layers. - * @param layer The konva layer to clone. - * @param filterChildren A callback to filter out unwanted children - * @returns The cloned stage and layer. - */ -const getIsolatedLayerClone = ( - layer: Konva.Layer, - filterChildren: (node: Konva.Node) => boolean -): { stageClone: Konva.Stage; layerClone: Konva.Layer } => { - const stage = layer.getStage(); - - // Construct an offscreen canvas with the same dimensions as the layer's stage. - const offscreenStageContainer = document.createElement('div'); - const stageClone = new Konva.Stage({ - container: offscreenStageContainer, - x: stage.x(), - y: stage.y(), - width: stage.width(), - height: stage.height(), - }); - - // Clone the layer and filter out unwanted children. - const layerClone = layer.clone(); - stageClone.add(layerClone); - - for (const child of layerClone.getChildren()) { - if (filterChildren(child) && child.hasChildren()) { - // We need to cache the group to ensure it composites out eraser strokes correctly - child.opacity(1); - child.cache(); - } else { - // Filter out unwanted children. - child.destroy(); - } - } - - return { stageClone, layerClone }; -}; - -/** - * Get the bounding box of a regional prompt konva layer. This function has special handling for regional prompt layers. - * @param layer The konva layer to get the bounding box of. - * @param preview Whether to open a new tab displaying the rendered layer, which is used to calculate the bbox. - */ -const getLayerBboxPixels = ( - layer: Konva.Layer, - filterChildren: (node: Konva.Node) => boolean, - preview: boolean = false -): IRect | null => { - // To calculate the layer's bounding box, we must first export it to a pixel array, then do some math. - // - // Though it is relatively fast, we can't use Konva's `getClientRect`. It programmatically determines the rect - // by calculating the extents of individual shapes from their "vector" shape data. - // - // This doesn't work when some shapes are drawn with composite operations that "erase" pixels, like eraser lines. - // These shapes' extents are still calculated as if they were solid, leading to a bounding box that is too large. - const { stageClone, layerClone } = getIsolatedLayerClone(layer, filterChildren); - - // Get a worst-case rect using the relatively fast `getClientRect`. - const layerRect = layerClone.getClientRect(); - if (layerRect.width === 0 || layerRect.height === 0) { - return null; - } - // Capture the image data with the above rect. - const layerImageData = stageClone - .toCanvas(layerRect) - .getContext('2d') - ?.getImageData(0, 0, layerRect.width, layerRect.height); - assert(layerImageData, "Unable to get layer's image data"); - - if (preview) { - openBase64ImageInTab([{ base64: imageDataToDataURL(layerImageData), caption: layer.id() }]); - } - - // Calculate the layer's bounding box. - const layerBbox = getImageDataBbox(layerImageData); - - if (!layerBbox) { - return null; - } - - // Correct the bounding box to be relative to the layer's position. - const correctedLayerBbox = { - x: layerBbox.minX - Math.floor(stageClone.x()) + layerRect.x - Math.floor(layer.x()), - y: layerBbox.minY - Math.floor(stageClone.y()) + layerRect.y - Math.floor(layer.y()), - width: layerBbox.maxX - layerBbox.minX, - height: layerBbox.maxY - layerBbox.minY, - }; - - return correctedLayerBbox; -}; - -/** - * Get the bounding box of a konva node. This function is faster than `getLayerBboxPixels` but less accurate. It - * should only be used when there are no eraser strokes or shapes in the node. - * @param node The konva node to get the bounding box of. - * @returns The bounding box of the node. - */ -export const getNodeBboxFast = (node: Konva.Node): IRect => { - const bbox = node.getClientRect(GET_CLIENT_RECT_CONFIG); - return bbox; -}; - -// TODO(psyche): fix this -const filterRGChildren = (node: Konva.Node): boolean => true; -const filterLayerChildren = (node: Konva.Node): boolean => true; -const filterCAChildren = (node: Konva.Node): boolean => true; - -/** - * Calculates the bbox of each regional guidance layer. Only calculates if the mask has changed. - * @param stage The konva stage - * @param entityStates An array of layers to calculate bboxes for - * @param onBboxChanged Callback for when the bounding box changes - */ -export const updateBboxes = ( - stage: Konva.Stage, - layers: CanvasLayerState[], - controlAdapters: CanvasControlAdapterState[], - regions: CanvasRegionalGuidanceState[], - onBboxChanged: (arg: BboxChangedArg, entityType: CanvasEntityState['type']) => void -): void => { - for (const entityState of [...layers, ...controlAdapters, ...regions]) { - const konvaLayer = stage.findOne(`#${entityState.id}`); - assert(konvaLayer, `Layer ${entityState.id} not found in stage`); - // We only need to recalculate the bbox if the layer has changed - if (entityState.bboxNeedsUpdate) { - const bboxRect = konvaLayer.findOne('.bbox') ?? createBboxRect(entityState, konvaLayer); - - // Hide the bbox while we calculate the new bbox, else the bbox will be included in the calculation - const visible = bboxRect.visible(); - bboxRect.visible(false); - - if (entityState.type === 'layer') { - if (entityState.objects.length === 0) { - // No objects - no bbox to calculate - onBboxChanged({ id: entityState.id, bbox: null }, 'layer'); - } else { - onBboxChanged({ id: entityState.id, bbox: getLayerBboxPixels(konvaLayer, filterLayerChildren) }, 'layer'); - } - } else if (entityState.type === 'control_adapter') { - if (!entityState.imageObject && !entityState.processedImageObject) { - // No objects - no bbox to calculate - onBboxChanged({ id: entityState.id, bbox: null }, 'control_adapter'); - } else { - onBboxChanged( - { id: entityState.id, bbox: getLayerBboxPixels(konvaLayer, filterCAChildren) }, - 'control_adapter' - ); - } - } else if (entityState.type === 'regional_guidance') { - if (entityState.objects.length === 0) { - // No objects - no bbox to calculate - onBboxChanged({ id: entityState.id, bbox: null }, 'regional_guidance'); - } else { - onBboxChanged( - { id: entityState.id, bbox: getLayerBboxPixels(konvaLayer, filterRGChildren) }, - 'regional_guidance' - ); - } - } - - // Restore the visibility of the bbox - bboxRect.visible(visible); - } - } -}; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts index 6e8fd2e3fb..8252f4627f 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts @@ -5,7 +5,6 @@ import { deepClone } from 'common/util/deepClone'; import { bboxReducers } from 'features/controlLayers/store/bboxReducers'; import { compositingReducers } from 'features/controlLayers/store/compositingReducers'; import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers'; -import { initialImageReducers } from 'features/controlLayers/store/initialImageReducers'; import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers'; import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers'; import { layersReducers } from 'features/controlLayers/store/layersReducers'; @@ -33,14 +32,6 @@ const initialState: CanvasV2State = { ipAdapters: { entities: [] }, regions: { entities: [] }, loras: [], - initialImage: { - id: 'initial_image', - type: 'initial_image', - bbox: null, - bboxNeedsUpdate: false, - isEnabled: true, - imageObject: null, - }, inpaintMask: { id: 'inpaint_mask', type: 'inpaint_mask', @@ -125,7 +116,6 @@ const initialState: CanvasV2State = { refinerStart: 0.8, }, session: { - isActive: false, isStaging: false, stagedImages: [], selectedStagedImageIndex: 0, @@ -148,7 +138,6 @@ export const canvasV2Slice = createSlice({ ...bboxReducers, ...inpaintMaskReducers, ...sessionReducers, - ...initialImageReducers, entitySelected: (state, action: PayloadAction) => { state.selectedEntityIdentifier = action.payload; }, @@ -175,7 +164,6 @@ export const canvasV2Slice = createSlice({ state.session = deepClone(initialState.session); state.tool = deepClone(initialState.tool); state.inpaintMask = deepClone(initialState.inpaintMask); - state.initialImage = deepClone(initialState.initialImage); }, }, }); @@ -342,18 +330,12 @@ export const { imRectAdded, inpaintMaskRasterized, // Staging - sessionStarted, sessionStartedStaging, sessionImageStaged, sessionStagedImageDiscarded, sessionStagingAreaReset, sessionNextStagedImageSelected, sessionPrevStagedImageSelected, - // Initial image - iiRecalled, - iiIsEnabledToggled, - iiReset, - iiImageChanged, } = canvasV2Slice.actions; export const selectCanvasV2Slice = (state: RootState) => state.canvasV2; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/initialImageReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/initialImageReducers.ts deleted file mode 100644 index f50edeefaa..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/store/initialImageReducers.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; -import { isEqual } from 'lodash-es'; -import type { ImageDTO } from 'services/api/types'; - -import type { CanvasV2State, InitialImageEntity } from './types'; -import { imageDTOToImageObject } from './types'; - -export const initialImageReducers = { - iiRecalled: (state, action: PayloadAction<{ data: InitialImageEntity }>) => { - const { data } = action.payload; - state.initialImage = data; - state.selectedEntityIdentifier = { type: 'initial_image', id: 'initial_image' }; - }, - iiIsEnabledToggled: (state) => { - if (!state.initialImage) { - return; - } - state.initialImage.isEnabled = !state.initialImage.isEnabled; - }, - iiReset: (state) => { - state.initialImage.imageObject = null; - }, - iiImageChanged: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => { - const { imageDTO } = action.payload; - if (!state.initialImage) { - return; - } - const newImageObject = imageDTOToImageObject(imageDTO); - if (isEqual(newImageObject, state.initialImage.imageObject)) { - return; - } - state.initialImage.bbox = null; - state.initialImage.bboxNeedsUpdate = true; - state.initialImage.isEnabled = true; - state.initialImage.imageObject = newImageObject; - state.selectedEntityIdentifier = { type: 'initial_image', id: 'initial_image' }; - }, -} satisfies SliceCaseReducers; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts index 03236aeaa2..7b21cb12c6 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts @@ -2,10 +2,6 @@ import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; import type { CanvasV2State, StagingAreaImage } from 'features/controlLayers/store/types'; export const sessionReducers = { - sessionStarted: (state) => { - state.session.isActive = true; - state.selectedEntityIdentifier = { id: 'inpaint_mask', type: 'inpaint_mask' }; - }, sessionStartedStaging: (state) => { state.session.isStaging = true; state.session.selectedStagedImageIndex = 0; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 993294832a..e1a32fd22e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -2,7 +2,6 @@ import type { JSONObject } from 'common/types'; import type { CanvasControlAdapter } from 'features/controlLayers/konva/CanvasControlAdapter'; import { CanvasLayerAdapter } from 'features/controlLayers/konva/CanvasLayerAdapter'; import { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter'; -import { CanvasRegion } from 'features/controlLayers/konva/CanvasRegion'; import { getObjectId } from 'features/controlLayers/konva/util'; import { zModelIdentifierField } from 'features/nodes/types/common'; import type { AspectRatioState } from 'features/parameters/components/DocumentSize/types'; @@ -686,16 +685,6 @@ const zCanvasInpaintMaskState = z.object({ }); export type CanvasInpaintMaskState = z.infer; -const zInitialImageEntity = z.object({ - id: z.literal('initial_image'), - type: z.literal('initial_image'), - isEnabled: z.boolean(), - bbox: zRect.nullable(), - bboxNeedsUpdate: z.boolean(), - imageObject: zCanvasImageState.nullable(), -}); -export type InitialImageEntity = z.infer; - const zCanvasControlAdapterStateBase = z.object({ id: zId, type: z.literal('control_adapter'), @@ -818,8 +807,7 @@ export type CanvasEntityState = | CanvasControlAdapterState | CanvasRegionalGuidanceState | CanvasInpaintMaskState - | CanvasIPAdapterState - | InitialImageEntity; + | CanvasIPAdapterState; export type CanvasEntityIdentifier = Pick; export type LoRA = { @@ -847,7 +835,6 @@ export type CanvasV2State = { ipAdapters: { entities: CanvasIPAdapterState[] }; regions: { entities: CanvasRegionalGuidanceState[] }; loras: LoRA[]; - initialImage: InitialImageEntity; tool: { selected: Tool; selectedBuffer: Tool | null; @@ -920,7 +907,6 @@ export type CanvasV2State = { refinerStart: number; }; session: { - isActive: boolean; isStaging: boolean; stagedImages: StagingAreaImage[]; selectedStagedImageIndex: number; @@ -969,11 +955,9 @@ export function isDrawableEntity( } export function isDrawableEntityAdapter( - adapter: CanvasLayerAdapter | CanvasRegion | CanvasControlAdapter | CanvasMaskAdapter -): adapter is CanvasLayerAdapter | CanvasRegion | CanvasMaskAdapter { - return ( - adapter instanceof CanvasLayerAdapter || adapter instanceof CanvasRegion || adapter instanceof CanvasMaskAdapter - ); + adapter: CanvasLayerAdapter | CanvasControlAdapter | CanvasMaskAdapter +): adapter is CanvasLayerAdapter | CanvasMaskAdapter { + return adapter instanceof CanvasLayerAdapter || adapter instanceof CanvasMaskAdapter; } export function isDrawableEntityType(