mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Fixes app after removing in/out-painting refs
This commit is contained in:
parent
98e3bbb3bd
commit
223e0529ba
@ -616,10 +616,7 @@ class InvokeAIWebServer:
|
|||||||
"""
|
"""
|
||||||
Prepare for generation based on generation_mode
|
Prepare for generation based on generation_mode
|
||||||
"""
|
"""
|
||||||
if generation_parameters["generation_mode"] in [
|
if generation_parameters["generation_mode"] == "unifiedCanvas":
|
||||||
"outpainting",
|
|
||||||
"inpainting",
|
|
||||||
]:
|
|
||||||
"""
|
"""
|
||||||
generation_parameters["init_img"] is a base64 image
|
generation_parameters["init_img"] is a base64 image
|
||||||
generation_parameters["init_mask"] 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()
|
original_bounding_box = generation_parameters["bounding_box"].copy()
|
||||||
|
|
||||||
if generation_parameters["generation_mode"] == "outpainting":
|
initial_image = dataURL_to_image(
|
||||||
initial_image = dataURL_to_image(
|
generation_parameters["init_img"]
|
||||||
generation_parameters["init_img"]
|
).convert("RGBA")
|
||||||
).convert("RGBA")
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The outpaint image and mask are pre-cropped by the UI, so the bounding box we pass
|
The outpaint image and mask are pre-cropped by the UI, so the bounding box we pass
|
||||||
to the generator should be:
|
to the generator should be:
|
||||||
{
|
{
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 0,
|
||||||
"width": original_bounding_box["width"],
|
"width": original_bounding_box["width"],
|
||||||
"height": original_bounding_box["height"]
|
"height": original_bounding_box["height"]
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
generation_parameters["bounding_box"]["x"] = 0
|
generation_parameters["bounding_box"]["x"] = 0
|
||||||
generation_parameters["bounding_box"]["y"] = 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"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Convert mask dataURL to an image and convert to greyscale
|
# Convert mask dataURL to an image and convert to greyscale
|
||||||
mask_image = dataURL_to_image(
|
mask_image = dataURL_to_image(
|
||||||
@ -930,7 +915,7 @@ class InvokeAIWebServer:
|
|||||||
if "init_mask" in all_parameters:
|
if "init_mask" in all_parameters:
|
||||||
all_parameters["init_mask"] = "" # TODO: store the mask in metadata
|
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
|
all_parameters["bounding_box"] = original_bounding_box
|
||||||
|
|
||||||
metadata = self.parameters_to_generated_image_metadata(all_parameters)
|
metadata = self.parameters_to_generated_image_metadata(all_parameters)
|
||||||
|
@ -50,7 +50,7 @@ const appSelector = createSelector(
|
|||||||
|
|
||||||
const shouldShowGalleryButton =
|
const shouldShowGalleryButton =
|
||||||
!(shouldShowGallery || (shouldHoldGalleryOpen && !shouldPinGallery)) &&
|
!(shouldShowGallery || (shouldHoldGalleryOpen && !shouldPinGallery)) &&
|
||||||
['txt2img', 'img2img', 'inpainting', 'outpainting'].includes(
|
['txt2img', 'img2img', 'unifiedCanvas'].includes(
|
||||||
activeTabName
|
activeTabName
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ const appSelector = createSelector(
|
|||||||
shouldShowOptionsPanel ||
|
shouldShowOptionsPanel ||
|
||||||
(shouldHoldOptionsPanelOpen && !shouldPinOptionsPanel)
|
(shouldHoldOptionsPanelOpen && !shouldPinOptionsPanel)
|
||||||
) &&
|
) &&
|
||||||
['txt2img', 'img2img', 'inpainting', 'outpainting'].includes(
|
['txt2img', 'img2img', 'unifiedCanvas'].includes(
|
||||||
activeTabName
|
activeTabName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -44,11 +44,6 @@ export const readinessSelector = createSelector(
|
|||||||
reasonsWhyNotReady.push('No initial image selected');
|
reasonsWhyNotReady.push('No initial image selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeTabName === 'inpainting' && !initialCanvasImage) {
|
|
||||||
isReady = false;
|
|
||||||
reasonsWhyNotReady.push('No inpainting image selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: job queue
|
// TODO: job queue
|
||||||
// Cannot generate if already processing an image
|
// Cannot generate if already processing an image
|
||||||
if (isProcessing) {
|
if (isProcessing) {
|
||||||
|
@ -54,24 +54,26 @@ const makeSocketIOEmitters = (
|
|||||||
systemState,
|
systemState,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (generationMode === 'inpainting') {
|
// if (generationMode === 'inpainting') {
|
||||||
const initialCanvasImage = initialCanvasImageSelector(getState());
|
// const initialCanvasImage = initialCanvasImageSelector(getState());
|
||||||
const imageUrl = initialCanvasImage?.image.url;
|
// const imageUrl = initialCanvasImage?.image.url;
|
||||||
|
|
||||||
if (!imageUrl) {
|
// if (!imageUrl) {
|
||||||
dispatch(
|
// dispatch(
|
||||||
addLogEntry({
|
// addLogEntry({
|
||||||
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
// timestamp: dateFormat(new Date(), 'isoDateTime'),
|
||||||
message: 'Inpainting image not loaded, cannot generate image.',
|
// message: 'Inpainting image not loaded, cannot generate image.',
|
||||||
level: 'error',
|
// level: 'error',
|
||||||
})
|
// })
|
||||||
);
|
// );
|
||||||
dispatch(errorOccurred());
|
// dispatch(errorOccurred());
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
frontendToBackendParametersConfig.imageToProcessUrl = imageUrl;
|
// frontendToBackendParametersConfig.imageToProcessUrl = imageUrl;
|
||||||
} else if (!['txt2img', 'img2img'].includes(generationMode)) {
|
// } else
|
||||||
|
|
||||||
|
if (!['txt2img', 'img2img'].includes(generationMode)) {
|
||||||
if (!galleryState.currentImage?.url) return;
|
if (!galleryState.currentImage?.url) return;
|
||||||
|
|
||||||
frontendToBackendParametersConfig.imageToProcessUrl =
|
frontendToBackendParametersConfig.imageToProcessUrl =
|
||||||
|
@ -37,10 +37,7 @@ import {
|
|||||||
requestNewImages,
|
requestNewImages,
|
||||||
requestSystemConfig,
|
requestSystemConfig,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import {
|
import { addImageToStagingArea } from 'features/canvas/canvasSlice';
|
||||||
addImageToStagingArea,
|
|
||||||
setImageToInpaint,
|
|
||||||
} from 'features/canvas/canvasSlice';
|
|
||||||
import { tabMap } from 'features/tabs/InvokeTabs';
|
import { tabMap } from 'features/tabs/InvokeTabs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,23 +117,15 @@ const makeSocketIOListeners = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (generationMode === 'unifiedCanvas' && data.boundingBox) {
|
||||||
['inpainting', 'outpainting'].includes(generationMode) &&
|
|
||||||
data.boundingBox
|
|
||||||
) {
|
|
||||||
newImage.category = 'temp';
|
newImage.category = 'temp';
|
||||||
const { boundingBox } = data;
|
const { boundingBox } = data;
|
||||||
|
dispatch(
|
||||||
if (generationMode === 'inpainting') {
|
addImageToStagingArea({
|
||||||
dispatch(setImageToInpaint(newImage));
|
image: newImage,
|
||||||
} else {
|
boundingBox,
|
||||||
dispatch(
|
})
|
||||||
addImageToStagingArea({
|
);
|
||||||
image: newImage,
|
|
||||||
boundingBox,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldLoopback) {
|
if (shouldLoopback) {
|
||||||
@ -146,10 +135,6 @@ const makeSocketIOListeners = (
|
|||||||
dispatch(setInitialImage(newImage));
|
dispatch(setInitialImage(newImage));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'inpainting': {
|
|
||||||
dispatch(setImageToInpaint(newImage));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,14 +28,8 @@ import { socketioMiddleware } from './socketio/middleware';
|
|||||||
* The necesssary nested persistors with blacklists are configured below.
|
* The necesssary nested persistors with blacklists are configured below.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const genericCanvasBlacklist = ['cursorPosition'];
|
const canvasBlacklist = ['cursorPosition'].map(
|
||||||
|
(blacklistItem) => `canvas.${blacklistItem}`
|
||||||
const inpaintingCanvasBlacklist = genericCanvasBlacklist.map(
|
|
||||||
(blacklistItem) => `canvas.inpainting.${blacklistItem}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const outpaintingCanvasBlacklist = genericCanvasBlacklist.map(
|
|
||||||
(blacklistItem) => `canvas.outpainting.${blacklistItem}`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const systemBlacklist = [
|
const systemBlacklist = [
|
||||||
@ -73,12 +67,7 @@ const rootPersistConfig = getPersistConfig({
|
|||||||
key: 'root',
|
key: 'root',
|
||||||
storage,
|
storage,
|
||||||
rootReducer,
|
rootReducer,
|
||||||
blacklist: [
|
blacklist: [...canvasBlacklist, ...systemBlacklist, ...galleryBlacklist],
|
||||||
...inpaintingCanvasBlacklist,
|
|
||||||
...outpaintingCanvasBlacklist,
|
|
||||||
...systemBlacklist,
|
|
||||||
...galleryBlacklist,
|
|
||||||
],
|
|
||||||
debounce: 300,
|
debounce: 300,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
|
|||||||
};
|
};
|
||||||
}, [dispatch, toast, activeTabName]);
|
}, [dispatch, toast, activeTabName]);
|
||||||
|
|
||||||
const overlaySecondaryText = ['img2img', 'inpainting'].includes(activeTabName)
|
const overlaySecondaryText = ['img2img', 'unifiedCanvas'].includes(activeTabName)
|
||||||
? ` to ${tabDict[activeTabName as keyof typeof tabDict].tooltip}`
|
? ` to ${tabDict[activeTabName as keyof typeof tabDict].tooltip}`
|
||||||
: ``;
|
: ``;
|
||||||
|
|
||||||
|
BIN
frontend/src/common/icons/UnifiedCanvas.afdesign
Normal file
BIN
frontend/src/common/icons/UnifiedCanvas.afdesign
Normal file
Binary file not shown.
16
frontend/src/common/icons/UnifiedCanvasIcon.tsx
Normal file
16
frontend/src/common/icons/UnifiedCanvasIcon.tsx
Normal file
File diff suppressed because one or more lines are too long
BIN
frontend/src/common/icons/design_files/UnifiedCanvas.afdesign
Normal file
BIN
frontend/src/common/icons/design_files/UnifiedCanvas.afdesign
Normal file
Binary file not shown.
7
frontend/src/common/icons/design_files/UnifiedCanvas.svg
Normal file
7
frontend/src/common/icons/design_files/UnifiedCanvas.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 9.8 KiB |
@ -106,10 +106,7 @@ export const frontendToBackendParameters = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// inpainting exclusive parameters
|
// inpainting exclusive parameters
|
||||||
if (
|
if (generationMode === 'unifiedCanvas' && canvasImageLayerRef.current) {
|
||||||
['inpainting', 'outpainting'].includes(generationMode) &&
|
|
||||||
canvasImageLayerRef.current
|
|
||||||
) {
|
|
||||||
const {
|
const {
|
||||||
layerState: { objects },
|
layerState: { objects },
|
||||||
boundingBoxCoordinates,
|
boundingBoxCoordinates,
|
||||||
@ -146,44 +143,42 @@ export const frontendToBackendParameters = (
|
|||||||
|
|
||||||
generationParameters.bounding_box = boundingBox;
|
generationParameters.bounding_box = boundingBox;
|
||||||
|
|
||||||
if (generationMode === 'outpainting') {
|
const tempScale = canvasImageLayerRef.current.scale();
|
||||||
const tempScale = canvasImageLayerRef.current.scale();
|
|
||||||
|
|
||||||
canvasImageLayerRef.current.scale({
|
canvasImageLayerRef.current.scale({
|
||||||
x: 1 / stageScale,
|
x: 1 / stageScale,
|
||||||
y: 1 / stageScale,
|
y: 1 / stageScale,
|
||||||
});
|
});
|
||||||
|
|
||||||
const absPos = canvasImageLayerRef.current.getAbsolutePosition();
|
const absPos = canvasImageLayerRef.current.getAbsolutePosition();
|
||||||
|
|
||||||
const imageDataURL = canvasImageLayerRef.current.toDataURL({
|
const imageDataURL = canvasImageLayerRef.current.toDataURL({
|
||||||
x: boundingBox.x + absPos.x,
|
x: boundingBox.x + absPos.x,
|
||||||
y: boundingBox.y + absPos.y,
|
y: boundingBox.y + absPos.y,
|
||||||
width: boundingBox.width,
|
width: boundingBox.width,
|
||||||
height: boundingBox.height,
|
height: boundingBox.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (enableImageDebugging) {
|
if (enableImageDebugging) {
|
||||||
openBase64ImageInTab([
|
openBase64ImageInTab([
|
||||||
{ base64: maskDataURL, caption: 'mask sent as init_mask' },
|
{ base64: maskDataURL, caption: 'mask sent as init_mask' },
|
||||||
{ base64: imageDataURL, caption: 'image sent as init_img' },
|
{ 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
if (shouldGenerateVariations) {
|
||||||
|
@ -93,7 +93,6 @@ const selector = createSelector(
|
|||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
tool,
|
tool,
|
||||||
isOnOutpaintingTab: activeTabName === 'outpainting',
|
|
||||||
isStaging,
|
isStaging,
|
||||||
shouldShowIntermediates,
|
shouldShowIntermediates,
|
||||||
shouldLockToInitialImage,
|
shouldLockToInitialImage,
|
||||||
@ -122,7 +121,6 @@ const IAICanvas = () => {
|
|||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
tool,
|
tool,
|
||||||
isOnOutpaintingTab,
|
|
||||||
isStaging,
|
isStaging,
|
||||||
shouldShowIntermediates,
|
shouldShowIntermediates,
|
||||||
shouldLockToInitialImage,
|
shouldLockToInitialImage,
|
||||||
@ -207,11 +205,7 @@ const IAICanvas = () => {
|
|||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
listening={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
|
listening={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
|
||||||
draggable={
|
draggable={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
|
||||||
(tool === 'move' || isStaging) &&
|
|
||||||
!isModifyingBoundingBox &&
|
|
||||||
isOnOutpaintingTab
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Layer id={'grid'} visible={shouldShowGrid}>
|
<Layer id={'grid'} visible={shouldShowGrid}>
|
||||||
<IAICanvasGrid />
|
<IAICanvasGrid />
|
||||||
@ -243,7 +237,7 @@ const IAICanvas = () => {
|
|||||||
/>
|
/>
|
||||||
</Layer>
|
</Layer>
|
||||||
</Stage>
|
</Stage>
|
||||||
{isOnOutpaintingTab && <IAICanvasStatusText />}
|
<IAICanvasStatusText />
|
||||||
<IAICanvasStagingAreaToolbar />
|
<IAICanvasStagingAreaToolbar />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import IAICanvasMaskColorPicker from './IAICanvasMaskControls/IAICanvasMaskColorPicker';
|
import IAICanvasMaskColorPicker from './IAICanvasMaskControls/IAICanvasMaskColorPicker';
|
||||||
|
|
||||||
const inpaintingBrushSelector = createSelector(
|
const selector = createSelector(
|
||||||
[canvasSelector, activeTabNameSelector],
|
[canvasSelector, activeTabNameSelector],
|
||||||
(canvas, activeTabName) => {
|
(canvas, activeTabName) => {
|
||||||
const { tool, brushSize } = canvas;
|
const { tool, brushSize } = canvas;
|
||||||
@ -38,9 +38,7 @@ const inpaintingBrushSelector = createSelector(
|
|||||||
|
|
||||||
export default function IAICanvasBrushControl() {
|
export default function IAICanvasBrushControl() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { tool, brushSize, activeTabName } = useAppSelector(
|
const { tool, brushSize, activeTabName } = useAppSelector(selector);
|
||||||
inpaintingBrushSelector
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectBrushTool = () => dispatch(setTool('brush'));
|
const handleSelectBrushTool = () => dispatch(setTool('brush'));
|
||||||
|
|
||||||
|
@ -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}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
@ -40,7 +40,7 @@ export default function IAICanvasMaskVisibilityControl() {
|
|||||||
handleToggleShouldShowMask();
|
handleToggleShouldShowMask();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: activeTabName === 'inpainting' || activeTabName == 'outpainting',
|
enabled: activeTabName === 'unifiedCanvas',
|
||||||
},
|
},
|
||||||
[activeTabName, isMaskEnabled]
|
[activeTabName, isMaskEnabled]
|
||||||
);
|
);
|
||||||
|
@ -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 {}
|
|
@ -52,9 +52,6 @@ const IAICanvasResizer = () => {
|
|||||||
|
|
||||||
if (!initialCanvasImage?.image) return;
|
if (!initialCanvasImage?.image) return;
|
||||||
|
|
||||||
const { width: imageWidth, height: imageHeight } =
|
|
||||||
initialCanvasImage.image;
|
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
setCanvasContainerDimensions({
|
setCanvasContainerDimensions({
|
||||||
width: clientWidth,
|
width: clientWidth,
|
||||||
@ -69,34 +66,6 @@ const IAICanvasResizer = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispatch(setDoesCanvasNeedScaling(false));
|
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);
|
}, 0);
|
||||||
}, [
|
}, [
|
||||||
dispatch,
|
dispatch,
|
||||||
@ -104,6 +73,7 @@ const IAICanvasResizer = () => {
|
|||||||
doesCanvasNeedScaling,
|
doesCanvasNeedScaling,
|
||||||
activeTabName,
|
activeTabName,
|
||||||
isCanvasInitialized,
|
isCanvasInitialized,
|
||||||
|
shouldLockToInitialImage,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
} from 'common/util/roundDownToMultiple';
|
} from 'common/util/roundDownToMultiple';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
export const setInitialCanvasImage = (
|
export const setInitialCanvasImage_reducer = (
|
||||||
state: CanvasState,
|
state: CanvasState,
|
||||||
image: InvokeAI.Image
|
image: InvokeAI.Image
|
||||||
) => {
|
) => {
|
||||||
|
@ -8,13 +8,11 @@ import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
|
|||||||
import { RootState } from 'app/store';
|
import { RootState } from 'app/store';
|
||||||
import { mergeAndUploadCanvas } from './util/mergeAndUploadCanvas';
|
import { mergeAndUploadCanvas } from './util/mergeAndUploadCanvas';
|
||||||
import { uploadImage } from 'features/gallery/util/uploadImage';
|
import { uploadImage } from 'features/gallery/util/uploadImage';
|
||||||
import { setInitialCanvasImage } from './canvasReducers';
|
import { setInitialCanvasImage_reducer } from './canvasReducers';
|
||||||
import calculateScale from './util/calculateScale';
|
import calculateScale from './util/calculateScale';
|
||||||
import calculateCoordinates from './util/calculateCoordinates';
|
import calculateCoordinates from './util/calculateCoordinates';
|
||||||
import floorCoordinates from './util/floorCoordinates';
|
import floorCoordinates from './util/floorCoordinates';
|
||||||
|
|
||||||
export type CanvasMode = 'inpainting' | 'outpainting';
|
|
||||||
|
|
||||||
export type CanvasLayer = 'base' | 'mask';
|
export type CanvasLayer = 'base' | 'mask';
|
||||||
|
|
||||||
export type CanvasDrawingTool = 'brush' | 'eraser';
|
export type CanvasDrawingTool = 'brush' | 'eraser';
|
||||||
@ -256,15 +254,8 @@ export const canvasSlice = createSlice({
|
|||||||
setCursorPosition: (state, action: PayloadAction<Vector2d | null>) => {
|
setCursorPosition: (state, action: PayloadAction<Vector2d | null>) => {
|
||||||
state.cursorPosition = action.payload;
|
state.cursorPosition = action.payload;
|
||||||
},
|
},
|
||||||
clearImageToInpaint: (state) => {
|
setInitialCanvasImage: (state, action: PayloadAction<InvokeAI.Image>) => {
|
||||||
// TODO
|
setInitialCanvasImage_reducer(state, action.payload);
|
||||||
// state.inpainting.imageToInpaint = undefined;
|
|
||||||
},
|
|
||||||
setImageToOutpaint: (state, action: PayloadAction<InvokeAI.Image>) => {
|
|
||||||
setInitialCanvasImage(state, action.payload);
|
|
||||||
},
|
|
||||||
setImageToInpaint: (state, action: PayloadAction<InvokeAI.Image>) => {
|
|
||||||
setInitialCanvasImage(state, action.payload);
|
|
||||||
},
|
},
|
||||||
setStageDimensions: (state, action: PayloadAction<Dimensions>) => {
|
setStageDimensions: (state, action: PayloadAction<Dimensions>) => {
|
||||||
state.stageDimensions = action.payload;
|
state.stageDimensions = action.payload;
|
||||||
@ -642,10 +633,8 @@ export const canvasSlice = createSlice({
|
|||||||
|
|
||||||
if (kind !== 'init') return;
|
if (kind !== 'init') return;
|
||||||
|
|
||||||
if (activeTabName === 'inpainting') {
|
if (activeTabName === 'unifiedCanvas') {
|
||||||
setInitialCanvasImage(state, image);
|
setInitialCanvasImage_reducer(state, image);
|
||||||
} else if (activeTabName === 'outpainting') {
|
|
||||||
setInitialCanvasImage(state, image);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -665,13 +654,11 @@ export const {
|
|||||||
setShouldShowBrushPreview,
|
setShouldShowBrushPreview,
|
||||||
setMaskColor,
|
setMaskColor,
|
||||||
clearMask,
|
clearMask,
|
||||||
clearImageToInpaint,
|
|
||||||
undo,
|
undo,
|
||||||
redo,
|
redo,
|
||||||
setCursorPosition,
|
setCursorPosition,
|
||||||
setStageDimensions,
|
setStageDimensions,
|
||||||
setImageToInpaint,
|
setInitialCanvasImage,
|
||||||
setImageToOutpaint,
|
|
||||||
setBoundingBoxDimensions,
|
setBoundingBoxDimensions,
|
||||||
setBoundingBoxCoordinates,
|
setBoundingBoxCoordinates,
|
||||||
setBoundingBoxPreviewFill,
|
setBoundingBoxPreviewFill,
|
||||||
|
@ -13,7 +13,7 @@ import { canvasSelector } from '../canvasSlice';
|
|||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { stageRef } from '../IAICanvas';
|
import { stageRef } from '../IAICanvas';
|
||||||
|
|
||||||
const inpaintingCanvasHotkeysSelector = createSelector(
|
const selector = createSelector(
|
||||||
[canvasSelector, activeTabNameSelector],
|
[canvasSelector, activeTabNameSelector],
|
||||||
(canvas, activeTabName) => {
|
(canvas, activeTabName) => {
|
||||||
const {
|
const {
|
||||||
@ -40,9 +40,8 @@ const inpaintingCanvasHotkeysSelector = createSelector(
|
|||||||
|
|
||||||
const useInpaintingCanvasHotkeys = () => {
|
const useInpaintingCanvasHotkeys = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { activeTabName, shouldShowBoundingBox, tool } = useAppSelector(
|
const { activeTabName, shouldShowBoundingBox, tool } =
|
||||||
inpaintingCanvasHotkeysSelector
|
useAppSelector(selector);
|
||||||
);
|
|
||||||
|
|
||||||
const previousToolRef = useRef<CanvasTool | null>(null);
|
const previousToolRef = useRef<CanvasTool | null>(null);
|
||||||
// Toggle lock bounding box
|
// Toggle lock bounding box
|
||||||
|
@ -60,12 +60,7 @@ const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
|
|||||||
return useCallback(
|
return useCallback(
|
||||||
(e: KonvaEventObject<WheelEvent>) => {
|
(e: KonvaEventObject<WheelEvent>) => {
|
||||||
// stop default scrolling
|
// stop default scrolling
|
||||||
if (
|
if (!stageRef.current || isMoveStageKeyHeld || !initialCanvasImage)
|
||||||
activeTabName !== 'outpainting' ||
|
|
||||||
!stageRef.current ||
|
|
||||||
isMoveStageKeyHeld ||
|
|
||||||
!initialCanvasImage
|
|
||||||
)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e.evt.preventDefault();
|
e.evt.preventDefault();
|
||||||
|
@ -36,9 +36,9 @@ import {
|
|||||||
FaTrash,
|
FaTrash,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import {
|
import {
|
||||||
setImageToInpaint,
|
|
||||||
setDoesCanvasNeedScaling,
|
setDoesCanvasNeedScaling,
|
||||||
setImageToOutpaint,
|
setInitialCanvasImage,
|
||||||
|
setShouldLockToInitialImage,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import { GalleryState } from './gallerySlice';
|
import { GalleryState } from './gallerySlice';
|
||||||
import { activeTabNameSelector } from 'features/options/optionsSelectors';
|
import { activeTabNameSelector } from 'features/options/optionsSelectors';
|
||||||
@ -320,12 +320,12 @@ const CurrentImageButtons = () => {
|
|||||||
if (!currentImage) return;
|
if (!currentImage) return;
|
||||||
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
||||||
|
|
||||||
dispatch(setImageToInpaint(currentImage));
|
dispatch(setInitialCanvasImage(currentImage));
|
||||||
dispatch(setActiveTab('inpainting'));
|
dispatch(setShouldLockToInitialImage(true));
|
||||||
dispatch(setDoesCanvasNeedScaling(true));
|
dispatch(setDoesCanvasNeedScaling(true));
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Sent to Inpainting',
|
title: 'Sent to Unified Canvas',
|
||||||
status: 'success',
|
status: 'success',
|
||||||
duration: 2500,
|
duration: 2500,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
@ -336,12 +336,12 @@ const CurrentImageButtons = () => {
|
|||||||
if (!currentImage) return;
|
if (!currentImage) return;
|
||||||
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
||||||
|
|
||||||
dispatch(setImageToOutpaint(currentImage));
|
dispatch(setInitialCanvasImage(currentImage));
|
||||||
dispatch(setActiveTab('outpainting'));
|
dispatch(setShouldLockToInitialImage(false));
|
||||||
dispatch(setDoesCanvasNeedScaling(true));
|
dispatch(setDoesCanvasNeedScaling(true));
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Sent to Inpainting',
|
title: 'Sent to Unified Canvas',
|
||||||
status: 'success',
|
status: 'success',
|
||||||
duration: 2500,
|
duration: 2500,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
|
@ -23,8 +23,9 @@ import {
|
|||||||
import * as InvokeAI from 'app/invokeai';
|
import * as InvokeAI from 'app/invokeai';
|
||||||
import * as ContextMenu from '@radix-ui/react-context-menu';
|
import * as ContextMenu from '@radix-ui/react-context-menu';
|
||||||
import {
|
import {
|
||||||
setImageToInpaint,
|
setDoesCanvasNeedScaling,
|
||||||
setImageToOutpaint,
|
setInitialCanvasImage,
|
||||||
|
setShouldLockToInitialImage,
|
||||||
} from 'features/canvas/canvasSlice';
|
} from 'features/canvas/canvasSlice';
|
||||||
import { hoverableImageSelector } from './gallerySliceSelectors';
|
import { hoverableImageSelector } from './gallerySliceSelectors';
|
||||||
|
|
||||||
@ -97,10 +98,15 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
|
|
||||||
const handleSendToInpainting = () => {
|
const handleSendToInpainting = () => {
|
||||||
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
||||||
dispatch(setImageToInpaint(image));
|
|
||||||
if (activeTabName !== 'inpainting') {
|
dispatch(setInitialCanvasImage(image));
|
||||||
dispatch(setActiveTab('inpainting'));
|
dispatch(setShouldLockToInitialImage(true));
|
||||||
|
dispatch(setDoesCanvasNeedScaling(true));
|
||||||
|
|
||||||
|
if (activeTabName !== 'unifiedCanvas') {
|
||||||
|
dispatch(setActiveTab('unifiedCanvas'));
|
||||||
}
|
}
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Sent to Inpainting',
|
title: 'Sent to Inpainting',
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -111,10 +117,15 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
|
|
||||||
const handleSendToOutpainting = () => {
|
const handleSendToOutpainting = () => {
|
||||||
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
if (isLightBoxOpen) dispatch(setIsLightBoxOpen(false));
|
||||||
dispatch(setImageToOutpaint(image));
|
|
||||||
if (activeTabName !== 'outpainting') {
|
dispatch(setInitialCanvasImage(image));
|
||||||
dispatch(setActiveTab('outpainting'));
|
dispatch(setShouldLockToInitialImage(true));
|
||||||
|
dispatch(setDoesCanvasNeedScaling(true));
|
||||||
|
|
||||||
|
if (activeTabName !== 'unifiedCanvas') {
|
||||||
|
dispatch(setActiveTab('unifiedCanvas'));
|
||||||
}
|
}
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Sent to Outpainting',
|
title: 'Sent to Outpainting',
|
||||||
status: 'success',
|
status: 'success',
|
||||||
|
@ -76,7 +76,7 @@ export default function ImageGallery() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeTabName === 'inpainting' || activeTabName === 'outpainting') {
|
if (activeTabName === 'unifiedCanvas') {
|
||||||
dispatch(setGalleryWidth(190));
|
dispatch(setGalleryWidth(190));
|
||||||
setGalleryMinWidth(190);
|
setGalleryMinWidth(190);
|
||||||
setGalleryMaxWidth(190);
|
setGalleryMaxWidth(190);
|
||||||
|
@ -15,7 +15,7 @@ export default function MainHeight() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<IAISelect
|
<IAISelect
|
||||||
isDisabled={activeTabName === 'inpainting'}
|
isDisabled={activeTabName === 'unifiedCanvas'}
|
||||||
label="Height"
|
label="Height"
|
||||||
value={height}
|
value={height}
|
||||||
flexGrow={1}
|
flexGrow={1}
|
||||||
|
@ -16,7 +16,7 @@ export default function MainWidth() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<IAISelect
|
<IAISelect
|
||||||
isDisabled={activeTabName === 'inpainting'}
|
isDisabled={activeTabName === 'unifiedCanvas'}
|
||||||
label="Width"
|
label="Width"
|
||||||
value={width}
|
value={width}
|
||||||
flexGrow={1}
|
flexGrow={1}
|
||||||
|
@ -142,7 +142,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const inpaintingHotkeys = [
|
const unifiedCanvasHotkeys = [
|
||||||
{
|
{
|
||||||
title: 'Select Brush',
|
title: 'Select Brush',
|
||||||
desc: 'Selects the inpainting brush',
|
desc: 'Selects the inpainting brush',
|
||||||
@ -223,9 +223,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
|||||||
desc: 'Expand your inpainting work area',
|
desc: 'Expand your inpainting work area',
|
||||||
hotkey: 'Shift+J',
|
hotkey: 'Shift+J',
|
||||||
},
|
},
|
||||||
];
|
|
||||||
|
|
||||||
const outpaintingHotkeys = [
|
|
||||||
{
|
{
|
||||||
title: 'Erase Canvas',
|
title: 'Erase Canvas',
|
||||||
desc: 'Erase the images on the canvas',
|
desc: 'Erase the images on the canvas',
|
||||||
@ -301,17 +298,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
|||||||
<AccordionIcon />
|
<AccordionIcon />
|
||||||
</AccordionButton>
|
</AccordionButton>
|
||||||
<AccordionPanel>
|
<AccordionPanel>
|
||||||
{renderHotkeyModalItems(inpaintingHotkeys)}
|
{renderHotkeyModalItems(unifiedCanvasHotkeys)}
|
||||||
</AccordionPanel>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem>
|
|
||||||
<AccordionButton className="hotkeys-modal-button">
|
|
||||||
<h2>Outpainting Hotkeys</h2>
|
|
||||||
<AccordionIcon />
|
|
||||||
</AccordionButton>
|
|
||||||
<AccordionPanel>
|
|
||||||
{renderHotkeyModalItems(outpaintingHotkeys)}
|
|
||||||
</AccordionPanel>
|
</AccordionPanel>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
@ -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;
|
|
@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
@ -17,12 +17,12 @@ import {
|
|||||||
setShouldShowOptionsPanel,
|
setShouldShowOptionsPanel,
|
||||||
} from 'features/options/optionsSlice';
|
} from 'features/options/optionsSlice';
|
||||||
import ImageToImageWorkarea from './ImageToImage';
|
import ImageToImageWorkarea from './ImageToImage';
|
||||||
import InpaintingWorkarea from './Inpainting/InpaintingWorkarea';
|
|
||||||
import TextToImageWorkarea from './TextToImage';
|
import TextToImageWorkarea from './TextToImage';
|
||||||
import Lightbox from 'features/lightbox/Lightbox';
|
import Lightbox from 'features/lightbox/Lightbox';
|
||||||
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
|
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
|
||||||
import OutpaintingWorkarea from './Outpainting/OutpaintingWorkarea';
|
import UnifiedCanvasWorkarea from './UnifiedCanvas/UnifiedCanvasWorkarea';
|
||||||
import { setShouldShowGallery } from 'features/gallery/gallerySlice';
|
import { setShouldShowGallery } from 'features/gallery/gallerySlice';
|
||||||
|
import UnifiedCanvasIcon from 'common/icons/UnifiedCanvasIcon';
|
||||||
|
|
||||||
export const tabDict = {
|
export const tabDict = {
|
||||||
txt2img: {
|
txt2img: {
|
||||||
@ -35,15 +35,10 @@ export const tabDict = {
|
|||||||
workarea: <ImageToImageWorkarea />,
|
workarea: <ImageToImageWorkarea />,
|
||||||
tooltip: 'Image To Image',
|
tooltip: 'Image To Image',
|
||||||
},
|
},
|
||||||
inpainting: {
|
unifiedCanvas: {
|
||||||
title: <InpaintIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <UnifiedCanvasIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||||
workarea: <InpaintingWorkarea />,
|
workarea: <UnifiedCanvasWorkarea />,
|
||||||
tooltip: 'Inpainting',
|
tooltip: 'Unified Canvas',
|
||||||
},
|
|
||||||
outpainting: {
|
|
||||||
title: <OutpaintIcon fill={'black'} boxSize={'2.5rem'} />,
|
|
||||||
workarea: <OutpaintingWorkarea />,
|
|
||||||
tooltip: 'Outpainting',
|
|
||||||
},
|
},
|
||||||
nodes: {
|
nodes: {
|
||||||
title: <NodesIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <NodesIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||||
|
@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
@ -12,7 +12,7 @@ import {
|
|||||||
import IAICanvas from 'features/canvas/IAICanvas';
|
import IAICanvas from 'features/canvas/IAICanvas';
|
||||||
import IAICanvasOutpaintingControls from 'features/canvas/IAICanvasOutpaintingControls';
|
import IAICanvasOutpaintingControls from 'features/canvas/IAICanvasOutpaintingControls';
|
||||||
|
|
||||||
const outpaintingDisplaySelector = createSelector(
|
const selector = createSelector(
|
||||||
[canvasSelector],
|
[canvasSelector],
|
||||||
(canvas) => {
|
(canvas) => {
|
||||||
const {
|
const {
|
||||||
@ -31,11 +31,10 @@ const outpaintingDisplaySelector = createSelector(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const OutpaintingDisplay = () => {
|
const UnifiedCanvasDisplay = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { doesCanvasNeedScaling, doesOutpaintingHaveObjects } = useAppSelector(
|
const { doesCanvasNeedScaling, doesOutpaintingHaveObjects } =
|
||||||
outpaintingDisplaySelector
|
useAppSelector(selector);
|
||||||
);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const resizeCallback = _.debounce(
|
const resizeCallback = _.debounce(
|
||||||
@ -46,17 +45,6 @@ const OutpaintingDisplay = () => {
|
|||||||
return () => window.removeEventListener('resize', resizeCallback);
|
return () => window.removeEventListener('resize', resizeCallback);
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const outpaintingComponent = doesOutpaintingHaveObjects ? (
|
|
||||||
<div className="inpainting-main-area">
|
|
||||||
<IAICanvasOutpaintingControls />
|
|
||||||
<div className="inpainting-canvas-area">
|
|
||||||
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<ImageUploadButton />
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'workarea-single-view'}>
|
<div className={'workarea-single-view'}>
|
||||||
<div className="workarea-split-view-left">
|
<div className="workarea-split-view-left">
|
||||||
@ -67,9 +55,8 @@ const OutpaintingDisplay = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="workarea-split-view-left">{outpaintingComponent}</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default OutpaintingDisplay;
|
export default UnifiedCanvasDisplay;
|
@ -18,7 +18,7 @@ import ProcessButtons from 'features/options/ProcessButtons/ProcessButtons';
|
|||||||
import PromptInput from 'features/options/PromptInput/PromptInput';
|
import PromptInput from 'features/options/PromptInput/PromptInput';
|
||||||
import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel';
|
import InvokeOptionsPanel from 'features/tabs/InvokeOptionsPanel';
|
||||||
|
|
||||||
export default function OutpaintingPanel() {
|
export default function UnifiedCanvasPanel() {
|
||||||
const showAdvancedOptions = useAppSelector(
|
const showAdvancedOptions = useAppSelector(
|
||||||
(state: RootState) => state.options.showAdvancedOptions
|
(state: RootState) => state.options.showAdvancedOptions
|
||||||
);
|
);
|
@ -1,21 +1,21 @@
|
|||||||
import InpaintingPanel from './InpaintingPanel';
|
import UnifiedCanvasPanel from './UnifiedCanvasPanel';
|
||||||
import InpaintingDisplay from './InpaintingDisplay';
|
import UnifiedCanvasDisplay from './UnifiedCanvasDisplay';
|
||||||
import InvokeWorkarea from 'features/tabs/InvokeWorkarea';
|
import InvokeWorkarea from 'features/tabs/InvokeWorkarea';
|
||||||
import { useAppDispatch } from 'app/store';
|
import { useAppDispatch } from 'app/store';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
|
import { setDoesCanvasNeedScaling } from 'features/canvas/canvasSlice';
|
||||||
|
|
||||||
export default function InpaintingWorkarea() {
|
export default function UnifiedCanvasWorkarea() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(setDoesCanvasNeedScaling(true));
|
dispatch(setDoesCanvasNeedScaling(true));
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
return (
|
return (
|
||||||
<InvokeWorkarea
|
<InvokeWorkarea
|
||||||
optionsPanel={<InpaintingPanel />}
|
optionsPanel={<UnifiedCanvasPanel />}
|
||||||
styleClass="inpainting-workarea-overrides"
|
styleClass="inpainting-workarea-overrides"
|
||||||
>
|
>
|
||||||
<InpaintingDisplay />
|
<UnifiedCanvasDisplay />
|
||||||
</InvokeWorkarea>
|
</InvokeWorkarea>
|
||||||
);
|
);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user