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:
blessedcoolant 2022-10-28 02:26:28 +13:00 committed by psychedelicious
parent 30bd79ffa1
commit 710e465054
12 changed files with 315 additions and 126 deletions

View File

@ -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;

View File

@ -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%;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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}
/>
</>
);
}

View File

@ -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>
</>

View File

@ -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>

View File

@ -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} />

View File

@ -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;

View File

@ -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,
};
},
{

View File

@ -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