Fixes app after removing in/out-painting refs

This commit is contained in:
psychedelicious 2022-11-17 12:42:47 +11:00 committed by blessedcoolant
parent 98e3bbb3bd
commit 223e0529ba
35 changed files with 170 additions and 509 deletions

View File

@ -616,10 +616,7 @@ class InvokeAIWebServer:
"""
Prepare for generation based on generation_mode
"""
if generation_parameters["generation_mode"] in [
"outpainting",
"inpainting",
]:
if generation_parameters["generation_mode"] == "unifiedCanvas":
"""
generation_parameters["init_img"] is a base64 image
generation_parameters["init_mask"] is a base64 image
@ -634,35 +631,23 @@ class InvokeAIWebServer:
original_bounding_box = generation_parameters["bounding_box"].copy()
if generation_parameters["generation_mode"] == "outpainting":
initial_image = dataURL_to_image(
generation_parameters["init_img"]
).convert("RGBA")
initial_image = dataURL_to_image(
generation_parameters["init_img"]
).convert("RGBA")
"""
The outpaint image and mask are pre-cropped by the UI, so the bounding box we pass
to the generator should be:
{
"x": 0,
"y": 0,
"width": original_bounding_box["width"],
"height": original_bounding_box["height"]
}
"""
"""
The outpaint image and mask are pre-cropped by the UI, so the bounding box we pass
to the generator should be:
{
"x": 0,
"y": 0,
"width": original_bounding_box["width"],
"height": original_bounding_box["height"]
}
"""
generation_parameters["bounding_box"]["x"] = 0
generation_parameters["bounding_box"]["y"] = 0
elif generation_parameters["generation_mode"] == "inpainting":
init_img_path = self.get_image_path_from_url(init_img_url)
initial_image = Image.open(init_img_path)
"""
For inpainting, only the mask is pre-cropped by the UI, so we need to crop out a copy
of the region of the image to be inpainted to match the size of the mask image.
"""
initial_image = copy_image_from_bounding_box(
initial_image, **generation_parameters["bounding_box"]
)
generation_parameters["bounding_box"]["x"] = 0
generation_parameters["bounding_box"]["y"] = 0
# Convert mask dataURL to an image and convert to greyscale
mask_image = dataURL_to_image(
@ -930,7 +915,7 @@ class InvokeAIWebServer:
if "init_mask" in all_parameters:
all_parameters["init_mask"] = "" # TODO: store the mask in metadata
if generation_parameters["generation_mode"] == "outpainting":
if generation_parameters["generation_mode"] == "unifiedCanvas":
all_parameters["bounding_box"] = original_bounding_box
metadata = self.parameters_to_generated_image_metadata(all_parameters)

View File

@ -50,7 +50,7 @@ const appSelector = createSelector(
const shouldShowGalleryButton =
!(shouldShowGallery || (shouldHoldGalleryOpen && !shouldPinGallery)) &&
['txt2img', 'img2img', 'inpainting', 'outpainting'].includes(
['txt2img', 'img2img', 'unifiedCanvas'].includes(
activeTabName
);
@ -59,7 +59,7 @@ const appSelector = createSelector(
shouldShowOptionsPanel ||
(shouldHoldOptionsPanelOpen && !shouldPinOptionsPanel)
) &&
['txt2img', 'img2img', 'inpainting', 'outpainting'].includes(
['txt2img', 'img2img', 'unifiedCanvas'].includes(
activeTabName
);

View File

@ -44,11 +44,6 @@ export const readinessSelector = createSelector(
reasonsWhyNotReady.push('No initial image selected');
}
if (activeTabName === 'inpainting' && !initialCanvasImage) {
isReady = false;
reasonsWhyNotReady.push('No inpainting image selected');
}
// TODO: job queue
// Cannot generate if already processing an image
if (isProcessing) {

View File

@ -54,24 +54,26 @@ const makeSocketIOEmitters = (
systemState,
};
if (generationMode === 'inpainting') {
const initialCanvasImage = initialCanvasImageSelector(getState());
const imageUrl = initialCanvasImage?.image.url;
// if (generationMode === 'inpainting') {
// const initialCanvasImage = initialCanvasImageSelector(getState());
// const imageUrl = initialCanvasImage?.image.url;
if (!imageUrl) {
dispatch(
addLogEntry({
timestamp: dateFormat(new Date(), 'isoDateTime'),
message: 'Inpainting image not loaded, cannot generate image.',
level: 'error',
})
);
dispatch(errorOccurred());
return;
}
// if (!imageUrl) {
// dispatch(
// addLogEntry({
// timestamp: dateFormat(new Date(), 'isoDateTime'),
// message: 'Inpainting image not loaded, cannot generate image.',
// level: 'error',
// })
// );
// dispatch(errorOccurred());
// return;
// }
frontendToBackendParametersConfig.imageToProcessUrl = imageUrl;
} else if (!['txt2img', 'img2img'].includes(generationMode)) {
// frontendToBackendParametersConfig.imageToProcessUrl = imageUrl;
// } else
if (!['txt2img', 'img2img'].includes(generationMode)) {
if (!galleryState.currentImage?.url) return;
frontendToBackendParametersConfig.imageToProcessUrl =

View File

@ -37,10 +37,7 @@ import {
requestNewImages,
requestSystemConfig,
} from './actions';
import {
addImageToStagingArea,
setImageToInpaint,
} from 'features/canvas/canvasSlice';
import { addImageToStagingArea } from 'features/canvas/canvasSlice';
import { tabMap } from 'features/tabs/InvokeTabs';
/**
@ -120,23 +117,15 @@ const makeSocketIOListeners = (
);
}
if (
['inpainting', 'outpainting'].includes(generationMode) &&
data.boundingBox
) {
if (generationMode === 'unifiedCanvas' && data.boundingBox) {
newImage.category = 'temp';
const { boundingBox } = data;
if (generationMode === 'inpainting') {
dispatch(setImageToInpaint(newImage));
} else {
dispatch(
addImageToStagingArea({
image: newImage,
boundingBox,
})
);
}
dispatch(
addImageToStagingArea({
image: newImage,
boundingBox,
})
);
}
if (shouldLoopback) {
@ -146,10 +135,6 @@ const makeSocketIOListeners = (
dispatch(setInitialImage(newImage));
break;
}
case 'inpainting': {
dispatch(setImageToInpaint(newImage));
break;
}
}
}

View File

@ -28,14 +28,8 @@ import { socketioMiddleware } from './socketio/middleware';
* The necesssary nested persistors with blacklists are configured below.
*/
const genericCanvasBlacklist = ['cursorPosition'];
const inpaintingCanvasBlacklist = genericCanvasBlacklist.map(
(blacklistItem) => `canvas.inpainting.${blacklistItem}`
);
const outpaintingCanvasBlacklist = genericCanvasBlacklist.map(
(blacklistItem) => `canvas.outpainting.${blacklistItem}`
const canvasBlacklist = ['cursorPosition'].map(
(blacklistItem) => `canvas.${blacklistItem}`
);
const systemBlacklist = [
@ -73,12 +67,7 @@ const rootPersistConfig = getPersistConfig({
key: 'root',
storage,
rootReducer,
blacklist: [
...inpaintingCanvasBlacklist,
...outpaintingCanvasBlacklist,
...systemBlacklist,
...galleryBlacklist,
],
blacklist: [...canvasBlacklist, ...systemBlacklist, ...galleryBlacklist],
debounce: 300,
});

View File

@ -135,7 +135,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
};
}, [dispatch, toast, activeTabName]);
const overlaySecondaryText = ['img2img', 'inpainting'].includes(activeTabName)
const overlaySecondaryText = ['img2img', 'unifiedCanvas'].includes(activeTabName)
? ` to ${tabDict[activeTabName as keyof typeof tabDict].tooltip}`
: ``;

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -106,10 +106,7 @@ export const frontendToBackendParameters = (
}
// inpainting exclusive parameters
if (
['inpainting', 'outpainting'].includes(generationMode) &&
canvasImageLayerRef.current
) {
if (generationMode === 'unifiedCanvas' && canvasImageLayerRef.current) {
const {
layerState: { objects },
boundingBoxCoordinates,
@ -146,44 +143,42 @@ export const frontendToBackendParameters = (
generationParameters.bounding_box = boundingBox;
if (generationMode === 'outpainting') {
const tempScale = canvasImageLayerRef.current.scale();
const tempScale = canvasImageLayerRef.current.scale();
canvasImageLayerRef.current.scale({
x: 1 / stageScale,
y: 1 / stageScale,
});
canvasImageLayerRef.current.scale({
x: 1 / stageScale,
y: 1 / stageScale,
});
const absPos = canvasImageLayerRef.current.getAbsolutePosition();
const absPos = canvasImageLayerRef.current.getAbsolutePosition();
const imageDataURL = canvasImageLayerRef.current.toDataURL({
x: boundingBox.x + absPos.x,
y: boundingBox.y + absPos.y,
width: boundingBox.width,
height: boundingBox.height,
});
const imageDataURL = canvasImageLayerRef.current.toDataURL({
x: boundingBox.x + absPos.x,
y: boundingBox.y + absPos.y,
width: boundingBox.width,
height: boundingBox.height,
});
if (enableImageDebugging) {
openBase64ImageInTab([
{ base64: maskDataURL, caption: 'mask sent as init_mask' },
{ base64: imageDataURL, caption: 'image sent as init_img' },
]);
}
canvasImageLayerRef.current.scale(tempScale);
generationParameters.init_img = imageDataURL;
// TODO: The server metadata generation needs to be changed to fix this.
generationParameters.progress_images = false;
generationParameters.seam_size = 96;
generationParameters.seam_blur = 16;
generationParameters.seam_strength = 0.7;
generationParameters.seam_steps = 10;
generationParameters.tile_size = 32;
generationParameters.force_outpaint = false;
if (enableImageDebugging) {
openBase64ImageInTab([
{ base64: maskDataURL, caption: 'mask sent as init_mask' },
{ base64: imageDataURL, caption: 'image sent as init_img' },
]);
}
canvasImageLayerRef.current.scale(tempScale);
generationParameters.init_img = imageDataURL;
// TODO: The server metadata generation needs to be changed to fix this.
generationParameters.progress_images = false;
generationParameters.seam_size = 96;
generationParameters.seam_blur = 16;
generationParameters.seam_strength = 0.7;
generationParameters.seam_steps = 10;
generationParameters.tile_size = 32;
generationParameters.force_outpaint = false;
}
if (shouldGenerateVariations) {

View File

@ -93,7 +93,6 @@ const selector = createSelector(
stageDimensions,
stageScale,
tool,
isOnOutpaintingTab: activeTabName === 'outpainting',
isStaging,
shouldShowIntermediates,
shouldLockToInitialImage,
@ -122,7 +121,6 @@ const IAICanvas = () => {
stageDimensions,
stageScale,
tool,
isOnOutpaintingTab,
isStaging,
shouldShowIntermediates,
shouldLockToInitialImage,
@ -207,11 +205,7 @@ const IAICanvas = () => {
onDragEnd={handleDragEnd}
onWheel={handleWheel}
listening={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
draggable={
(tool === 'move' || isStaging) &&
!isModifyingBoundingBox &&
isOnOutpaintingTab
}
draggable={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
>
<Layer id={'grid'} visible={shouldShowGrid}>
<IAICanvasGrid />
@ -243,7 +237,7 @@ const IAICanvas = () => {
/>
</Layer>
</Stage>
{isOnOutpaintingTab && <IAICanvasStatusText />}
<IAICanvasStatusText />
<IAICanvasStagingAreaToolbar />
</div>
</div>

View File

@ -18,7 +18,7 @@ import {
import _ from 'lodash';
import IAICanvasMaskColorPicker from './IAICanvasMaskControls/IAICanvasMaskColorPicker';
const inpaintingBrushSelector = createSelector(
const selector = createSelector(
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const { tool, brushSize } = canvas;
@ -38,9 +38,7 @@ const inpaintingBrushSelector = createSelector(
export default function IAICanvasBrushControl() {
const dispatch = useAppDispatch();
const { tool, brushSize, activeTabName } = useAppSelector(
inpaintingBrushSelector
);
const { tool, brushSize, activeTabName } = useAppSelector(selector);
const handleSelectBrushTool = () => dispatch(setTool('brush'));

View File

@ -1,21 +0,0 @@
import { FaTrash } from 'react-icons/fa';
import { useAppDispatch } from 'app/store';
import IAIIconButton from 'common/components/IAIIconButton';
import { clearImageToInpaint } from 'features/canvas/canvasSlice';
export default function IAICanvasClearImageControl() {
const dispatch = useAppDispatch();
const handleClearImage = () => {
dispatch(clearImageToInpaint());
};
return (
<IAIIconButton
aria-label="Clear Image"
tooltip="Clear Image"
icon={<FaTrash size={16} />}
onClick={handleClearImage}
/>
);
}

View File

@ -40,7 +40,7 @@ export default function IAICanvasMaskVisibilityControl() {
handleToggleShouldShowMask();
},
{
enabled: activeTabName === 'inpainting' || activeTabName == 'outpainting',
enabled: activeTabName === 'unifiedCanvas',
},
[activeTabName, isMaskEnabled]
);

View File

@ -1,49 +0,0 @@
// import { GroupConfig } from 'konva/lib/Group';
// import { Group, Line } from 'react-konva';
// import { RootState, useAppSelector } from 'app/store';
// import { createSelector } from '@reduxjs/toolkit';
// import { OutpaintingCanvasState } from './canvasSlice';
// export const canvasEraserLinesSelector = createSelector(
// (state: RootState) => state.canvas.outpainting,
// (outpainting: OutpaintingCanvasState) => {
// const { eraserLines } = outpainting;
// return {
// eraserLines,
// };
// }
// );
// type IAICanvasEraserLinesProps = GroupConfig;
// /**
// * Draws the lines which comprise the mask.
// *
// * Uses globalCompositeOperation to handle the brush and eraser tools.
// */
// const IAICanvasEraserLines = (props: IAICanvasEraserLinesProps) => {
// const { ...rest } = props;
// const { eraserLines } = useAppSelector(canvasEraserLinesSelector);
// return (
// <Group {...rest} globalCompositeOperation={'destination-out'}>
// {eraserLines.map((line, i) => (
// <Line
// key={i}
// points={line.points}
// stroke={'rgb(0,0,0)'} // The lines can be any color, just need alpha > 0
// strokeWidth={line.strokeWidth * 2}
// tension={0}
// lineCap="round"
// lineJoin="round"
// shadowForStrokeEnabled={false}
// listening={false}
// globalCompositeOperation={'source-over'}
// />
// ))}
// </Group>
// );
// };
// export default IAICanvasEraserLines;
export default {}

View File

@ -52,9 +52,6 @@ const IAICanvasResizer = () => {
if (!initialCanvasImage?.image) return;
const { width: imageWidth, height: imageHeight } =
initialCanvasImage.image;
dispatch(
setCanvasContainerDimensions({
width: clientWidth,
@ -69,34 +66,6 @@ const IAICanvasResizer = () => {
}
dispatch(setDoesCanvasNeedScaling(false));
// }
// if ((activeTabName === 'inpainting') && initialCanvasImage?.image) {
// const { width: imageWidth, height: imageHeight } =
// initialCanvasImage.image;
// const scale = Math.min(
// 1,
// Math.min(clientWidth / imageWidth, clientHeight / imageHeight)
// );
// dispatch(setStageScale(scale));
// dispatch(
// setStageDimensions({
// width: Math.floor(imageWidth * scale),
// height: Math.floor(imageHeight * scale),
// })
// );
// dispatch(setDoesCanvasNeedScaling(false));
// } else if (activeTabName === 'outpainting') {
// dispatch(
// setStageDimensions({
// width: Math.floor(clientWidth),
// height: Math.floor(clientHeight),
// })
// );
// dispatch(setDoesCanvasNeedScaling(false));
// }
}, 0);
}, [
dispatch,
@ -104,6 +73,7 @@ const IAICanvasResizer = () => {
doesCanvasNeedScaling,
activeTabName,
isCanvasInitialized,
shouldLockToInitialImage,
]);
return (

View File

@ -6,7 +6,7 @@ import {
} from 'common/util/roundDownToMultiple';
import _ from 'lodash';
export const setInitialCanvasImage = (
export const setInitialCanvasImage_reducer = (
state: CanvasState,
image: InvokeAI.Image
) => {

View File

@ -8,13 +8,11 @@ import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
import { RootState } from 'app/store';
import { mergeAndUploadCanvas } from './util/mergeAndUploadCanvas';
import { uploadImage } from 'features/gallery/util/uploadImage';
import { setInitialCanvasImage } from './canvasReducers';
import { setInitialCanvasImage_reducer } from './canvasReducers';
import calculateScale from './util/calculateScale';
import calculateCoordinates from './util/calculateCoordinates';
import floorCoordinates from './util/floorCoordinates';
export type CanvasMode = 'inpainting' | 'outpainting';
export type CanvasLayer = 'base' | 'mask';
export type CanvasDrawingTool = 'brush' | 'eraser';
@ -256,15 +254,8 @@ export const canvasSlice = createSlice({
setCursorPosition: (state, action: PayloadAction<Vector2d | null>) => {
state.cursorPosition = action.payload;
},
clearImageToInpaint: (state) => {
// TODO
// state.inpainting.imageToInpaint = undefined;
},
setImageToOutpaint: (state, action: PayloadAction<InvokeAI.Image>) => {
setInitialCanvasImage(state, action.payload);
},
setImageToInpaint: (state, action: PayloadAction<InvokeAI.Image>) => {
setInitialCanvasImage(state, action.payload);
setInitialCanvasImage: (state, action: PayloadAction<InvokeAI.Image>) => {
setInitialCanvasImage_reducer(state, action.payload);
},
setStageDimensions: (state, action: PayloadAction<Dimensions>) => {
state.stageDimensions = action.payload;
@ -642,10 +633,8 @@ export const canvasSlice = createSlice({
if (kind !== 'init') return;
if (activeTabName === 'inpainting') {
setInitialCanvasImage(state, image);
} else if (activeTabName === 'outpainting') {
setInitialCanvasImage(state, image);
if (activeTabName === 'unifiedCanvas') {
setInitialCanvasImage_reducer(state, image);
}
});
},
@ -665,13 +654,11 @@ export const {
setShouldShowBrushPreview,
setMaskColor,
clearMask,
clearImageToInpaint,
undo,
redo,
setCursorPosition,
setStageDimensions,
setImageToInpaint,
setImageToOutpaint,
setInitialCanvasImage,
setBoundingBoxDimensions,
setBoundingBoxCoordinates,
setBoundingBoxPreviewFill,

View File

@ -13,7 +13,7 @@ import { canvasSelector } from '../canvasSlice';
import { useRef } from 'react';
import { stageRef } from '../IAICanvas';
const inpaintingCanvasHotkeysSelector = createSelector(
const selector = createSelector(
[canvasSelector, activeTabNameSelector],
(canvas, activeTabName) => {
const {
@ -40,9 +40,8 @@ const inpaintingCanvasHotkeysSelector = createSelector(
const useInpaintingCanvasHotkeys = () => {
const dispatch = useAppDispatch();
const { activeTabName, shouldShowBoundingBox, tool } = useAppSelector(
inpaintingCanvasHotkeysSelector
);
const { activeTabName, shouldShowBoundingBox, tool } =
useAppSelector(selector);
const previousToolRef = useRef<CanvasTool | null>(null);
// Toggle lock bounding box

View File

@ -60,12 +60,7 @@ const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
return useCallback(
(e: KonvaEventObject<WheelEvent>) => {
// stop default scrolling
if (
activeTabName !== 'outpainting' ||
!stageRef.current ||
isMoveStageKeyHeld ||
!initialCanvasImage
)
if (!stageRef.current || isMoveStageKeyHeld || !initialCanvasImage)
return;
e.evt.preventDefault();

View File

@ -36,9 +36,9 @@ import {
FaTrash,
} from 'react-icons/fa';
import {
setImageToInpaint,
setDoesCanvasNeedScaling,
setImageToOutpaint,
setInitialCanvasImage,
setShouldLockToInitialImage,
} from 'features/canvas/canvasSlice';
import { GalleryState } from './gallerySlice';
import { activeTabNameSelector } from 'features/options/optionsSelectors';
@ -320,12 +320,12 @@ const CurrentImageButtons = () => {
if (!currentImage) return;
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
dispatch(setImageToInpaint(currentImage));
dispatch(setActiveTab('inpainting'));
dispatch(setInitialCanvasImage(currentImage));
dispatch(setShouldLockToInitialImage(true));
dispatch(setDoesCanvasNeedScaling(true));
toast({
title: 'Sent to Inpainting',
title: 'Sent to Unified Canvas',
status: 'success',
duration: 2500,
isClosable: true,
@ -336,12 +336,12 @@ const CurrentImageButtons = () => {
if (!currentImage) return;
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
dispatch(setImageToOutpaint(currentImage));
dispatch(setActiveTab('outpainting'));
dispatch(setInitialCanvasImage(currentImage));
dispatch(setShouldLockToInitialImage(false));
dispatch(setDoesCanvasNeedScaling(true));
toast({
title: 'Sent to Inpainting',
title: 'Sent to Unified Canvas',
status: 'success',
duration: 2500,
isClosable: true,

View File

@ -23,8 +23,9 @@ import {
import * as InvokeAI from 'app/invokeai';
import * as ContextMenu from '@radix-ui/react-context-menu';
import {
setImageToInpaint,
setImageToOutpaint,
setDoesCanvasNeedScaling,
setInitialCanvasImage,
setShouldLockToInitialImage,
} from 'features/canvas/canvasSlice';
import { hoverableImageSelector } from './gallerySliceSelectors';
@ -97,10 +98,15 @@ const HoverableImage = memo((props: HoverableImageProps) => {
const handleSendToInpainting = () => {
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
dispatch(setImageToInpaint(image));
if (activeTabName !== 'inpainting') {
dispatch(setActiveTab('inpainting'));
dispatch(setInitialCanvasImage(image));
dispatch(setShouldLockToInitialImage(true));
dispatch(setDoesCanvasNeedScaling(true));
if (activeTabName !== 'unifiedCanvas') {
dispatch(setActiveTab('unifiedCanvas'));
}
toast({
title: 'Sent to Inpainting',
status: 'success',
@ -111,10 +117,15 @@ const HoverableImage = memo((props: HoverableImageProps) => {
const handleSendToOutpainting = () => {
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
dispatch(setImageToOutpaint(image));
if (activeTabName !== 'outpainting') {
dispatch(setActiveTab('outpainting'));
dispatch(setInitialCanvasImage(image));
dispatch(setShouldLockToInitialImage(true));
dispatch(setDoesCanvasNeedScaling(true));
if (activeTabName !== 'unifiedCanvas') {
dispatch(setActiveTab('unifiedCanvas'));
}
toast({
title: 'Sent to Outpainting',
status: 'success',

View File

@ -76,7 +76,7 @@ export default function ImageGallery() {
return;
}
if (activeTabName === 'inpainting' || activeTabName === 'outpainting') {
if (activeTabName === 'unifiedCanvas') {
dispatch(setGalleryWidth(190));
setGalleryMinWidth(190);
setGalleryMaxWidth(190);

View File

@ -15,7 +15,7 @@ export default function MainHeight() {
return (
<IAISelect
isDisabled={activeTabName === 'inpainting'}
isDisabled={activeTabName === 'unifiedCanvas'}
label="Height"
value={height}
flexGrow={1}

View File

@ -16,7 +16,7 @@ export default function MainWidth() {
return (
<IAISelect
isDisabled={activeTabName === 'inpainting'}
isDisabled={activeTabName === 'unifiedCanvas'}
label="Width"
value={width}
flexGrow={1}

View File

@ -142,7 +142,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
},
];
const inpaintingHotkeys = [
const unifiedCanvasHotkeys = [
{
title: 'Select Brush',
desc: 'Selects the inpainting brush',
@ -223,9 +223,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: 'Expand your inpainting work area',
hotkey: 'Shift+J',
},
];
const outpaintingHotkeys = [
{
title: 'Erase Canvas',
desc: 'Erase the images on the canvas',
@ -301,17 +298,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
<AccordionIcon />
</AccordionButton>
<AccordionPanel>
{renderHotkeyModalItems(inpaintingHotkeys)}
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<AccordionButton className="hotkeys-modal-button">
<h2>Outpainting Hotkeys</h2>
<AccordionIcon />
</AccordionButton>
<AccordionPanel>
{renderHotkeyModalItems(outpaintingHotkeys)}
{renderHotkeyModalItems(unifiedCanvasHotkeys)}
</AccordionPanel>
</AccordionItem>
</Accordion>

View File

@ -1,80 +0,0 @@
import { createSelector } from '@reduxjs/toolkit';
import IAICanvasControls from 'features/canvas/IAICanvasControls';
import IAICanvasResizer from 'features/canvas/IAICanvasResizer';
import _ from 'lodash';
import { useLayoutEffect } from 'react';
import { RootState, useAppDispatch, useAppSelector } from 'app/store';
import ImageUploadButton from 'common/components/ImageUploaderButton';
import CurrentImageDisplay from 'features/gallery/CurrentImageDisplay';
import { OptionsState } from 'features/options/optionsSlice';
import {
initialCanvasImageSelector,
CanvasState,
setDoesCanvasNeedScaling,
} from 'features/canvas/canvasSlice';
import IAICanvas from 'features/canvas/IAICanvas';
const inpaintingDisplaySelector = createSelector(
[
initialCanvasImageSelector,
(state: RootState) => state.canvas,
(state: RootState) => state.options,
],
(initialCanvasImage, canvas: CanvasState, options: OptionsState) => {
const { doesCanvasNeedScaling } = canvas;
const { showDualDisplay } = options;
return {
doesCanvasNeedScaling,
showDualDisplay,
initialCanvasImage,
};
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
},
}
);
const InpaintingDisplay = () => {
const dispatch = useAppDispatch();
const { showDualDisplay, doesCanvasNeedScaling, initialCanvasImage } =
useAppSelector(inpaintingDisplaySelector);
useLayoutEffect(() => {
const resizeCallback = _.debounce(
() => dispatch(setDoesCanvasNeedScaling(true)),
250
);
window.addEventListener('resize', resizeCallback);
return () => window.removeEventListener('resize', resizeCallback);
}, [dispatch]);
const inpaintingComponent = initialCanvasImage ? (
<div className="inpainting-main-area">
<IAICanvasControls />
<div className="inpainting-canvas-area">
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
</div>
</div>
) : (
<ImageUploadButton />
);
return (
<div
className={
showDualDisplay ? 'workarea-split-view' : 'workarea-single-view'
}
>
<div className="workarea-split-view-left">{inpaintingComponent}</div>
{showDualDisplay && (
<div className="workarea-split-view-right">
<CurrentImageDisplay />
</div>
)}
</div>
);
};
export default InpaintingDisplay;

View File

@ -1,65 +0,0 @@
// import { Feature } from 'app/features';
import { Feature } from 'app/features';
import { RootState, useAppSelector } from 'app/store';
import FaceRestoreHeader from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreHeader';
import FaceRestoreOptions from 'features/options/AdvancedOptions/FaceRestore/FaceRestoreOptions';
import ImageToImageStrength from 'features/options/AdvancedOptions/ImageToImage/ImageToImageStrength';
import InpaintingSettings from 'features/options/AdvancedOptions/Inpainting/InpaintingSettings';
import SeedHeader from 'features/options/AdvancedOptions/Seed/SeedHeader';
import SeedOptions from 'features/options/AdvancedOptions/Seed/SeedOptions';
import UpscaleHeader from 'features/options/AdvancedOptions/Upscale/UpscaleHeader';
import UpscaleOptions from 'features/options/AdvancedOptions/Upscale/UpscaleOptions';
import VariationsHeader from 'features/options/AdvancedOptions/Variations/VariationsHeader';
import VariationsOptions from 'features/options/AdvancedOptions/Variations/VariationsOptions';
import MainAdvancedOptionsCheckbox from 'features/options/MainOptions/MainAdvancedOptionsCheckbox';
import MainOptions from 'features/options/MainOptions/MainOptions';
import OptionsAccordion from 'features/options/OptionsAccordion';
import ProcessButtons from 'features/options/ProcessButtons/ProcessButtons';
import PromptInput from 'features/options/PromptInput/PromptInput';
import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel';
export default function InpaintingPanel() {
const showAdvancedOptions = useAppSelector(
(state: RootState) => state.options.showAdvancedOptions
);
const imageToImageAccordions = {
seed: {
header: <SeedHeader />,
feature: Feature.SEED,
options: <SeedOptions />,
},
variations: {
header: <VariationsHeader />,
feature: Feature.VARIATIONS,
options: <VariationsOptions />,
},
face_restore: {
header: <FaceRestoreHeader />,
feature: Feature.FACE_CORRECTION,
options: <FaceRestoreOptions />,
},
upscale: {
header: <UpscaleHeader />,
feature: Feature.UPSCALE,
options: <UpscaleOptions />,
},
};
return (
<InvokeOptionsPanel>
<PromptInput />
<ProcessButtons />
<MainOptions />
<ImageToImageStrength
label="Image To Image Strength"
styleClass="main-option-block image-to-image-strength-main-option"
/>
<InpaintingSettings />
<MainAdvancedOptionsCheckbox />
{showAdvancedOptions && (
<OptionsAccordion accordionInfo={imageToImageAccordions} />
)}
</InvokeOptionsPanel>
);
}

View File

@ -17,12 +17,12 @@ import {
setShouldShowOptionsPanel,
} from 'features/options/optionsSlice';
import ImageToImageWorkarea from './ImageToImage';
import InpaintingWorkarea from './Inpainting/InpaintingWorkarea';
import TextToImageWorkarea from './TextToImage';
import Lightbox from 'features/lightbox/Lightbox';
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
import OutpaintingWorkarea from './Outpainting/OutpaintingWorkarea';
import UnifiedCanvasWorkarea from './UnifiedCanvas/UnifiedCanvasWorkarea';
import { setShouldShowGallery } from 'features/gallery/gallerySlice';
import UnifiedCanvasIcon from 'common/icons/UnifiedCanvasIcon';
export const tabDict = {
txt2img: {
@ -35,15 +35,10 @@ export const tabDict = {
workarea: <ImageToImageWorkarea />,
tooltip: 'Image To Image',
},
inpainting: {
title: <InpaintIcon fill={'black'} boxSize={'2.5rem'} />,
workarea: <InpaintingWorkarea />,
tooltip: 'Inpainting',
},
outpainting: {
title: <OutpaintIcon fill={'black'} boxSize={'2.5rem'} />,
workarea: <OutpaintingWorkarea />,
tooltip: 'Outpainting',
unifiedCanvas: {
title: <UnifiedCanvasIcon fill={'black'} boxSize={'2.5rem'} />,
workarea: <UnifiedCanvasWorkarea />,
tooltip: 'Unified Canvas',
},
nodes: {
title: <NodesIcon fill={'black'} boxSize={'2.5rem'} />,

View File

@ -1,21 +0,0 @@
import OutpaintingPanel from './OutpaintingPanel';
import OutpaintingDisplay from './OutpaintingDisplay';
import InvokeWorkarea from 'features/tabs/InvokeWorkarea';
import { useAppDispatch } from 'app/store';
import { useEffect } from 'react';
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
export default function OutpaintingWorkarea() {
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(setDoesCanvasNeedScaling(true));
}, [dispatch]);
return (
<InvokeWorkarea
optionsPanel={<OutpaintingPanel />}
styleClass="inpainting-workarea-overrides"
>
<OutpaintingDisplay />
</InvokeWorkarea>
);
}

View File

@ -12,7 +12,7 @@ import {
import IAICanvas from 'features/canvas/IAICanvas';
import IAICanvasOutpaintingControls from 'features/canvas/IAICanvasOutpaintingControls';
const outpaintingDisplaySelector = createSelector(
const selector = createSelector(
[canvasSelector],
(canvas) => {
const {
@ -31,11 +31,10 @@ const outpaintingDisplaySelector = createSelector(
}
);
const OutpaintingDisplay = () => {
const UnifiedCanvasDisplay = () => {
const dispatch = useAppDispatch();
const { doesCanvasNeedScaling, doesOutpaintingHaveObjects } = useAppSelector(
outpaintingDisplaySelector
);
const { doesCanvasNeedScaling, doesOutpaintingHaveObjects } =
useAppSelector(selector);
useLayoutEffect(() => {
const resizeCallback = _.debounce(
@ -46,17 +45,6 @@ const OutpaintingDisplay = () => {
return () => window.removeEventListener('resize', resizeCallback);
}, [dispatch]);
const outpaintingComponent = doesOutpaintingHaveObjects ? (
<div className="inpainting-main-area">
<IAICanvasOutpaintingControls />
<div className="inpainting-canvas-area">
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
</div>
</div>
) : (
<ImageUploadButton />
);
return (
<div className={'workarea-single-view'}>
<div className="workarea-split-view-left">
@ -67,9 +55,8 @@ const OutpaintingDisplay = () => {
</div>
</div>
</div>
{/* <div className="workarea-split-view-left">{outpaintingComponent}</div> */}
</div>
);
};
export default OutpaintingDisplay;
export default UnifiedCanvasDisplay;

View File

@ -18,7 +18,7 @@ import ProcessButtons from 'features/options/ProcessButtons/ProcessButtons';
import PromptInput from 'features/options/PromptInput/PromptInput';
import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel';
export default function OutpaintingPanel() {
export default function UnifiedCanvasPanel() {
const showAdvancedOptions = useAppSelector(
(state: RootState) => state.options.showAdvancedOptions
);

View File

@ -1,21 +1,21 @@
import InpaintingPanel from './InpaintingPanel';
import InpaintingDisplay from './InpaintingDisplay';
import UnifiedCanvasPanel from './UnifiedCanvasPanel';
import UnifiedCanvasDisplay from './UnifiedCanvasDisplay';
import InvokeWorkarea from 'features/tabs/InvokeWorkarea';
import { useAppDispatch } from 'app/store';
import { useEffect } from 'react';
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
export default function InpaintingWorkarea() {
export default function UnifiedCanvasWorkarea() {
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(setDoesCanvasNeedScaling(true));
}, [dispatch]);
return (
<InvokeWorkarea
optionsPanel={<InpaintingPanel />}
optionsPanel={<UnifiedCanvasPanel />}
styleClass="inpainting-workarea-overrides"
>
<InpaintingDisplay />
<UnifiedCanvasDisplay />
</InvokeWorkarea>
);
}