mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Add Inpainting Settings
- Enable and Disable Inpainting Box (with backend support) - Enable and Disable Bounding Box Darkening - Reset Bounding Box
This commit is contained in:
parent
30bd79ffa1
commit
710e465054
@ -101,13 +101,26 @@ export const frontendToBackendParameters = (
|
||||
lines,
|
||||
boundingBoxCoordinate: { x, y },
|
||||
boundingBoxDimensions: { width, height },
|
||||
shouldShowBoundingBox,
|
||||
} = inpaintingState;
|
||||
|
||||
let bx = x,
|
||||
by = y,
|
||||
bwidth = width,
|
||||
bheight = height;
|
||||
|
||||
if (!shouldShowBoundingBox) {
|
||||
bx = 0;
|
||||
by = 0;
|
||||
bwidth = maskImageElement.width;
|
||||
bheight = maskImageElement.height;
|
||||
}
|
||||
|
||||
const boundingBox = {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
x: bx,
|
||||
y: by,
|
||||
width: bwidth,
|
||||
height: bheight,
|
||||
};
|
||||
|
||||
generationParameters.init_img = imageToProcessUrl;
|
||||
|
@ -1,13 +0,0 @@
|
||||
.inpainting-bounding-box-dimensions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 1rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.inpainting-bounding-box-dimensions-slider-numberinput {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
column-gap: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
import { FormLabel } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
RootState,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
} from '../../../../app/store';
|
||||
import IAINumberInput from '../../../../common/components/IAINumberInput';
|
||||
import IAISlider from '../../../../common/components/IAISlider';
|
||||
import { roundDownToMultiple } from '../../../../common/util/roundDownToMultiple';
|
||||
import {
|
||||
InpaintingState,
|
||||
setBoundingBoxDimensions,
|
||||
} from '../../../tabs/Inpainting/inpaintingSlice';
|
||||
|
||||
const boundingBoxDimensionsSelector = createSelector(
|
||||
(state: RootState) => state.inpainting,
|
||||
(inpainting: InpaintingState) => {
|
||||
const { canvasDimensions, boundingBoxDimensions } = inpainting;
|
||||
return { canvasDimensions, boundingBoxDimensions };
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const BoundingBoxDimensions = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { canvasDimensions, boundingBoxDimensions } = useAppSelector(
|
||||
boundingBoxDimensionsSelector
|
||||
);
|
||||
|
||||
const handleChangeBoundingBoxWidth = (v: number) => {
|
||||
dispatch(setBoundingBoxDimensions({ ...boundingBoxDimensions, width: v }));
|
||||
};
|
||||
|
||||
const handleChangeBoundingBoxHeight = (v: number) => {
|
||||
dispatch(setBoundingBoxDimensions({ ...boundingBoxDimensions, height: v }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="inpainting-bounding-box-dimensions">
|
||||
Inpainting Bounding Box
|
||||
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
|
||||
<IAISlider
|
||||
label="Width"
|
||||
width={'8rem'}
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.width, 64)}
|
||||
step={64}
|
||||
value={boundingBoxDimensions.width}
|
||||
onChange={handleChangeBoundingBoxWidth}
|
||||
/>
|
||||
<IAINumberInput
|
||||
value={boundingBoxDimensions.width}
|
||||
onChange={handleChangeBoundingBoxWidth}
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.width, 64)}
|
||||
step={64}
|
||||
width={'5.5rem'}
|
||||
/>
|
||||
</div>
|
||||
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
|
||||
<IAISlider
|
||||
label="Height"
|
||||
width={'8rem'}
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.height, 64)}
|
||||
step={64}
|
||||
value={boundingBoxDimensions.height}
|
||||
onChange={handleChangeBoundingBoxHeight}
|
||||
/>
|
||||
<IAINumberInput
|
||||
value={boundingBoxDimensions.height}
|
||||
onChange={handleChangeBoundingBoxHeight}
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.height, 64)}
|
||||
step={64}
|
||||
width={'5.5rem'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoundingBoxDimensions;
|
@ -0,0 +1,44 @@
|
||||
.inpainting-bounding-box-settings {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 100%;
|
||||
border-radius: 0.4rem;
|
||||
border: 2px solid var(--tab-color);
|
||||
}
|
||||
|
||||
.inpainting-bounding-box-header {
|
||||
background-color: var(--tab-color);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.4rem 0.4rem 0 0;
|
||||
|
||||
p {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.inpainting-bounding-box-settings-items {
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 1rem;
|
||||
|
||||
.inpainting-bounding-box-reset-icon-btn {
|
||||
background-color: var(--btn-load-more) !important;
|
||||
&:hover {
|
||||
background-color: var(--btn-load-more-hover) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inpainting-bounding-box-dimensions-slider-numberinput {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
column-gap: 1rem;
|
||||
}
|
||||
|
||||
.inpainting-bounding-box-darken {
|
||||
width: max-content;
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import _ from 'lodash';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { BiReset } from 'react-icons/bi';
|
||||
|
||||
import {
|
||||
RootState,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
} from '../../../../app/store';
|
||||
import IAICheckbox from '../../../../common/components/IAICheckbox';
|
||||
import IAIIconButton from '../../../../common/components/IAIIconButton';
|
||||
|
||||
import IAINumberInput from '../../../../common/components/IAINumberInput';
|
||||
import IAISlider from '../../../../common/components/IAISlider';
|
||||
import IAISwitch from '../../../../common/components/IAISwitch';
|
||||
import { roundDownToMultiple } from '../../../../common/util/roundDownToMultiple';
|
||||
import {
|
||||
InpaintingState,
|
||||
setBoundingBoxDimensions,
|
||||
setShouldShowBoundingBox,
|
||||
setShouldShowBoundingBoxFill,
|
||||
} from '../../../tabs/Inpainting/inpaintingSlice';
|
||||
|
||||
const boundingBoxDimensionsSelector = createSelector(
|
||||
(state: RootState) => state.inpainting,
|
||||
(inpainting: InpaintingState) => {
|
||||
const {
|
||||
canvasDimensions,
|
||||
boundingBoxDimensions,
|
||||
shouldShowBoundingBox,
|
||||
shouldShowBoundingBoxFill,
|
||||
pastLines,
|
||||
futureLines,
|
||||
} = inpainting;
|
||||
return {
|
||||
canvasDimensions,
|
||||
boundingBoxDimensions,
|
||||
shouldShowBoundingBox,
|
||||
shouldShowBoundingBoxFill,
|
||||
pastLines,
|
||||
futureLines,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const BoundingBoxSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
canvasDimensions,
|
||||
boundingBoxDimensions,
|
||||
shouldShowBoundingBox,
|
||||
shouldShowBoundingBoxFill,
|
||||
} = useAppSelector(boundingBoxDimensionsSelector);
|
||||
|
||||
const handleChangeBoundingBoxWidth = (v: number) => {
|
||||
dispatch(setBoundingBoxDimensions({ ...boundingBoxDimensions, width: v }));
|
||||
};
|
||||
|
||||
const handleChangeBoundingBoxHeight = (v: number) => {
|
||||
dispatch(setBoundingBoxDimensions({ ...boundingBoxDimensions, height: v }));
|
||||
};
|
||||
|
||||
const handleShowBoundingBox = (e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldShowBoundingBox(e.target.checked));
|
||||
|
||||
const handleChangeShouldShowBoundingBoxFill = () => {
|
||||
dispatch(setShouldShowBoundingBoxFill(!shouldShowBoundingBoxFill));
|
||||
};
|
||||
|
||||
const handleResetWidth = () => {
|
||||
dispatch(
|
||||
setBoundingBoxDimensions({
|
||||
...boundingBoxDimensions,
|
||||
width: canvasDimensions.width,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResetHeight = () => {
|
||||
dispatch(
|
||||
setBoundingBoxDimensions({
|
||||
...boundingBoxDimensions,
|
||||
height: canvasDimensions.height,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="inpainting-bounding-box-settings">
|
||||
<div className="inpainting-bounding-box-header">
|
||||
<p>Inpaint Box</p>
|
||||
<IAISwitch
|
||||
isChecked={shouldShowBoundingBox}
|
||||
width={'auto'}
|
||||
onChange={handleShowBoundingBox}
|
||||
/>
|
||||
</div>
|
||||
<div className="inpainting-bounding-box-settings-items">
|
||||
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
|
||||
<IAISlider
|
||||
label="Box W"
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.width, 64)}
|
||||
step={64}
|
||||
value={boundingBoxDimensions.width}
|
||||
onChange={handleChangeBoundingBoxWidth}
|
||||
isDisabled={!shouldShowBoundingBox}
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAINumberInput
|
||||
value={boundingBoxDimensions.width}
|
||||
onChange={handleChangeBoundingBoxWidth}
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.width, 64)}
|
||||
step={64}
|
||||
isDisabled={!shouldShowBoundingBox}
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAIIconButton
|
||||
size={'sm'}
|
||||
aria-label={'Reset Width'}
|
||||
tooltip={'Reset Width'}
|
||||
onClick={handleResetWidth}
|
||||
icon={<BiReset />}
|
||||
styleClass="inpainting-bounding-box-reset-icon-btn"
|
||||
/>
|
||||
</div>
|
||||
<div className="inpainting-bounding-box-dimensions-slider-numberinput">
|
||||
<IAISlider
|
||||
label="Box H"
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.height, 64)}
|
||||
step={64}
|
||||
value={boundingBoxDimensions.height}
|
||||
onChange={handleChangeBoundingBoxHeight}
|
||||
isDisabled={!shouldShowBoundingBox}
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAINumberInput
|
||||
value={boundingBoxDimensions.height}
|
||||
onChange={handleChangeBoundingBoxHeight}
|
||||
min={64}
|
||||
max={roundDownToMultiple(canvasDimensions.height, 64)}
|
||||
step={64}
|
||||
padding="0"
|
||||
isDisabled={!shouldShowBoundingBox}
|
||||
width={'5rem'}
|
||||
/>
|
||||
<IAIIconButton
|
||||
size={'sm'}
|
||||
aria-label={'Reset Height'}
|
||||
tooltip={'Reset Height'}
|
||||
onClick={handleResetHeight}
|
||||
icon={<BiReset />}
|
||||
styleClass="inpainting-bounding-box-reset-icon-btn"
|
||||
/>
|
||||
</div>
|
||||
<IAICheckbox
|
||||
label="Darken Outside Box"
|
||||
isChecked={shouldShowBoundingBoxFill}
|
||||
onChange={handleChangeShouldShowBoundingBoxFill}
|
||||
styleClass="inpainting-bounding-box-darken"
|
||||
isDisabled={!shouldShowBoundingBox}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoundingBoxSettings;
|
@ -0,0 +1,59 @@
|
||||
import { useToast } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import React from 'react';
|
||||
import {
|
||||
RootState,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
} from '../../../../app/store';
|
||||
import IAIButton from '../../../../common/components/IAIButton';
|
||||
import {
|
||||
InpaintingState,
|
||||
setClearBrushHistory,
|
||||
} from '../../../tabs/Inpainting/inpaintingSlice';
|
||||
import BoundingBoxSettings from './BoundingBoxSettings';
|
||||
import _ from 'lodash';
|
||||
|
||||
const inpaintingSelector = createSelector(
|
||||
(state: RootState) => state.inpainting,
|
||||
(inpainting: InpaintingState) => {
|
||||
const { pastLines, futureLines } = inpainting;
|
||||
return {
|
||||
pastLines,
|
||||
futureLines,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export default function InpaintingSettings() {
|
||||
const dispatch = useAppDispatch();
|
||||
const toast = useToast();
|
||||
|
||||
const { pastLines, futureLines } = useAppSelector(inpaintingSelector);
|
||||
|
||||
const handleClearBrushHistory = () => {
|
||||
dispatch(setClearBrushHistory());
|
||||
toast({
|
||||
title: 'Brush Stroke History Cleared',
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<BoundingBoxSettings />
|
||||
<IAIButton
|
||||
label="Clear Brush History"
|
||||
onClick={handleClearBrushHistory}
|
||||
tooltip="Clears brush stroke history"
|
||||
disabled={futureLines.length > 0 || pastLines.length > 0 ? false : true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
@ -61,6 +61,7 @@ const InpaintingCanvas = () => {
|
||||
shouldShowBoundingBoxFill,
|
||||
isDrawing,
|
||||
isBoundingBoxTransforming,
|
||||
shouldShowBoundingBox,
|
||||
} = useAppSelector(inpaintingCanvasSelector);
|
||||
|
||||
// set the closure'd refs
|
||||
@ -280,10 +281,10 @@ const InpaintingCanvas = () => {
|
||||
)}
|
||||
</Layer>
|
||||
<Layer>
|
||||
{shouldShowBoundingBoxFill && (
|
||||
{shouldShowBoundingBox && shouldShowBoundingBoxFill && (
|
||||
<InpaintingBoundingBoxPreviewOverlay />
|
||||
)}
|
||||
<InpaintingBoundingBoxPreview />
|
||||
{shouldShowBoundingBox && <InpaintingBoundingBoxPreview />}
|
||||
<InpaintingCanvasBrushPreviewOutline />
|
||||
</Layer>
|
||||
</>
|
||||
|
@ -6,8 +6,6 @@ import {
|
||||
FaPalette,
|
||||
FaPlus,
|
||||
FaRedo,
|
||||
FaTint,
|
||||
FaTintSlash,
|
||||
FaUndo,
|
||||
} from 'react-icons/fa';
|
||||
import { BiHide, BiShow } from 'react-icons/bi';
|
||||
@ -25,7 +23,6 @@ import {
|
||||
setShouldShowMask,
|
||||
setShouldInvertMask,
|
||||
setNeedsRepaint,
|
||||
setShouldShowBoundingBoxFill,
|
||||
} from './inpaintingSlice';
|
||||
|
||||
import { MdInvertColors, MdInvertColorsOff } from 'react-icons/md';
|
||||
@ -49,7 +46,6 @@ const InpaintingControls = () => {
|
||||
isMaskEmpty,
|
||||
activeTabName,
|
||||
showDualDisplay,
|
||||
shouldShowBoundingBoxFill,
|
||||
} = useAppSelector(inpaintingControlsSelector);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
@ -268,10 +264,6 @@ const InpaintingControls = () => {
|
||||
dispatch(setNeedsRepaint(true));
|
||||
};
|
||||
|
||||
const handleChangeShouldShowBoundingBoxFill = () => {
|
||||
dispatch(setShouldShowBoundingBoxFill(!shouldShowBoundingBoxFill));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="inpainting-settings">
|
||||
<div className="inpainting-buttons">
|
||||
@ -390,13 +382,6 @@ const InpaintingControls = () => {
|
||||
data-selected={showDualDisplay}
|
||||
onClick={handleDualDisplay}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label="Darken Outside Bounding Box (xxx)"
|
||||
tooltip="Darken Outside Bounding Box (xxx)"
|
||||
icon={shouldShowBoundingBoxFill ? <FaTint /> : <FaTintSlash />}
|
||||
data-selected={shouldShowBoundingBoxFill}
|
||||
onClick={handleChangeShouldShowBoundingBoxFill}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@ import { RootState, useAppSelector } from '../../../app/store';
|
||||
import FaceRestoreHeader from '../../options/AdvancedOptions/FaceRestore/FaceRestoreHeader';
|
||||
import FaceRestoreOptions from '../../options/AdvancedOptions/FaceRestore/FaceRestoreOptions';
|
||||
import ImageToImageStrength from '../../options/AdvancedOptions/ImageToImage/ImageToImageStrength';
|
||||
import BoundingBoxDimensions from '../../options/AdvancedOptions/Inpainting/BoundingBoxDimensions';
|
||||
import InpaintingSettings from '../../options/AdvancedOptions/Inpainting/InpaintingSettings';
|
||||
import SeedHeader from '../../options/AdvancedOptions/Seed/SeedHeader';
|
||||
import SeedOptions from '../../options/AdvancedOptions/Seed/SeedOptions';
|
||||
import UpscaleHeader from '../../options/AdvancedOptions/Upscale/UpscaleHeader';
|
||||
@ -49,11 +49,11 @@ export default function InpaintingPanel() {
|
||||
<PromptInput />
|
||||
<ProcessButtons />
|
||||
<MainOptions />
|
||||
<BoundingBoxDimensions />
|
||||
<ImageToImageStrength
|
||||
label="Image To Image Strength"
|
||||
styleClass="main-option-block image-to-image-strength-main-option"
|
||||
/>
|
||||
<InpaintingSettings />
|
||||
<MainAdvancedOptionsCheckbox />
|
||||
{showAdvancedOptions ? (
|
||||
<OptionsAccordion accordionInfo={imageToImageAccordions} />
|
||||
|
@ -38,6 +38,7 @@ export interface InpaintingState {
|
||||
boundingBoxCoordinate: Vector2d;
|
||||
isMovingBoundingBox: boolean;
|
||||
boundingBoxPreviewFill: RgbaColor;
|
||||
shouldShowBoundingBox: boolean;
|
||||
shouldShowBoundingBoxFill: boolean;
|
||||
isBoundingBoxTransforming: boolean;
|
||||
lines: MaskLine[];
|
||||
@ -62,6 +63,7 @@ const initialInpaintingState: InpaintingState = {
|
||||
boundingBoxDimensions: { width: 64, height: 64 },
|
||||
boundingBoxCoordinate: { x: 0, y: 0 },
|
||||
boundingBoxPreviewFill: { r: 0, g: 0, b: 0, a: 0.7 },
|
||||
shouldShowBoundingBox: false,
|
||||
shouldShowBoundingBoxFill: false,
|
||||
isBoundingBoxTransforming: false,
|
||||
cursorPosition: null,
|
||||
@ -310,6 +312,13 @@ export const inpaintingSlice = createSlice({
|
||||
setIsDrawing: (state, action: PayloadAction<boolean>) => {
|
||||
state.isDrawing = action.payload;
|
||||
},
|
||||
setShouldShowBoundingBox: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowBoundingBox = action.payload;
|
||||
},
|
||||
setClearBrushHistory: (state) => {
|
||||
state.pastLines = [];
|
||||
state.futureLines = [];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -341,6 +350,8 @@ export const {
|
||||
setIsBoundingBoxTransforming,
|
||||
setIsDrawing,
|
||||
setShouldShowBrush,
|
||||
setShouldShowBoundingBox,
|
||||
setClearBrushHistory,
|
||||
} = inpaintingSlice.actions;
|
||||
|
||||
export default inpaintingSlice.reducer;
|
||||
|
@ -79,6 +79,7 @@ export const inpaintingCanvasSelector = createSelector(
|
||||
shouldShowBoundingBoxFill,
|
||||
isDrawing,
|
||||
isBoundingBoxTransforming,
|
||||
shouldShowBoundingBox,
|
||||
} = inpainting;
|
||||
return {
|
||||
tool,
|
||||
@ -97,6 +98,7 @@ export const inpaintingCanvasSelector = createSelector(
|
||||
shouldShowBoundingBoxFill,
|
||||
isDrawing,
|
||||
isBoundingBoxTransforming,
|
||||
shouldShowBoundingBox,
|
||||
};
|
||||
},
|
||||
{
|
||||
|
@ -22,7 +22,7 @@
|
||||
@use '../features/options/MainOptions/MainOptions.scss';
|
||||
@use '../features/options/AccordionItems/AdvancedSettings.scss';
|
||||
@use '../features/options/AdvancedOptions/Upscale/UpscaleOptions.scss';
|
||||
@use '../features/options/AdvancedOptions/Inpainting/BoundingBoxDimensions.scss';
|
||||
@use '../features/options/AdvancedOptions/Inpainting/BoundingBoxSettings.scss';
|
||||
@use '../features/system/ProgressBar.scss';
|
||||
|
||||
// gallery
|
||||
|
Loading…
Reference in New Issue
Block a user