mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Adds auto-scaling for inpaint size
This commit is contained in:
parent
46a5fd67ed
commit
d4280bbaaa
@ -14,7 +14,8 @@ export enum Feature {
|
||||
FACE_CORRECTION,
|
||||
IMAGE_TO_IMAGE,
|
||||
BOUNDING_BOX,
|
||||
CANVAS_COMPOSITION,
|
||||
SEAM_CORRECTION,
|
||||
INFILL_AND_SCALING,
|
||||
}
|
||||
/** For each tooltip in the UI, the below feature definitions & props will pull relevant information into the tooltip.
|
||||
*
|
||||
@ -57,17 +58,22 @@ export const FEATURES: Record<Feature, FeatureHelpInfo> = {
|
||||
guideImage: 'asset/path.gif',
|
||||
},
|
||||
[Feature.IMAGE_TO_IMAGE]: {
|
||||
text: 'ImageToImage allows the upload of an initial image, which InvokeAI will use to guide the generation process, along with a prompt. A lower value for this setting will more closely resemble the original image. Values between 0-1 are accepted, and a range of .25-.75 is recommended ',
|
||||
text: 'Image to Image allows the upload of an initial image, which InvokeAI will use to guide the generation process, along with a prompt. A lower value for this setting will more closely resemble the original image. Values between 0-1 are accepted, and a range of .25-.75 is recommended ',
|
||||
href: 'link/to/docs/feature3.html',
|
||||
guideImage: 'asset/path.gif',
|
||||
},
|
||||
[Feature.BOUNDING_BOX]: {
|
||||
text: 'The Bounding Box is analogous to the Width and Height settings for Text to Image or Image to Image. Only the area in the box will be processed.',
|
||||
text: 'The bounding box is analogous to the Width and Height settings for Text to Image or Image to Image. Only the area in the box will be processed.',
|
||||
href: 'link/to/docs/feature3.html',
|
||||
guideImage: 'asset/path.gif',
|
||||
},
|
||||
[Feature.CANVAS_COMPOSITION]: {
|
||||
text: 'Control the process used to cleanly manage seams between existing compositions and new invocations, using larger areas of the image for seam guidance, or applying various configurations on the generation process.',
|
||||
[Feature.SEAM_CORRECTION]: {
|
||||
text: 'Control the handling of visible seams which may occur when a generated image is pasted back onto the canvas.',
|
||||
href: 'link/to/docs/feature3.html',
|
||||
guideImage: 'asset/path.gif',
|
||||
},
|
||||
[Feature.INFILL_AND_SCALING]: {
|
||||
text: 'Manage infill methods (used on masked or erased areas of the canvas) and scaling (useful for small bounding box sizes).',
|
||||
href: 'link/to/docs/feature3.html',
|
||||
guideImage: 'asset/path.gif',
|
||||
},
|
||||
|
@ -14,6 +14,7 @@
|
||||
border: 2px solid var(--border-color);
|
||||
background-color: var(--background-color-secondary);
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
height: 2rem;
|
||||
border-radius: 0.2rem;
|
||||
|
||||
|
@ -127,7 +127,7 @@ export const frontendToBackendParameters = (
|
||||
stageScale,
|
||||
isMaskEnabled,
|
||||
shouldPreserveMaskedArea,
|
||||
shouldScaleBoundingBox,
|
||||
boundingBoxScaleMethod: boundingBoxScale,
|
||||
scaledBoundingBoxDimensions,
|
||||
} = canvasState;
|
||||
|
||||
@ -185,7 +185,7 @@ export const frontendToBackendParameters = (
|
||||
|
||||
generationParameters.progress_images = false;
|
||||
|
||||
if (shouldScaleBoundingBox) {
|
||||
if (boundingBoxScale !== 'none') {
|
||||
generationParameters.inpaint_width = scaledBoundingBoxDimensions.width;
|
||||
generationParameters.inpaint_height = scaledBoundingBoxDimensions.height;
|
||||
}
|
||||
|
@ -12,10 +12,15 @@ const selector = createSelector(
|
||||
stageDimensions: { width: stageWidth, height: stageHeight },
|
||||
stageCoordinates: { x: stageX, y: stageY },
|
||||
boundingBoxDimensions: { width: boxWidth, height: boxHeight },
|
||||
scaledBoundingBoxDimensions: {
|
||||
width: scaledBoxWidth,
|
||||
height: scaledBoxHeight,
|
||||
},
|
||||
boundingBoxCoordinates: { x: boxX, y: boxY },
|
||||
stageScale,
|
||||
shouldShowCanvasDebugInfo,
|
||||
layer,
|
||||
boundingBoxScaleMethod,
|
||||
} = canvas;
|
||||
|
||||
return {
|
||||
@ -30,12 +35,14 @@ const selector = createSelector(
|
||||
boxX
|
||||
)}, ${roundToHundreth(boxY)})`,
|
||||
boundingBoxDimensionsString: `${boxWidth}×${boxHeight}`,
|
||||
scaledBoundingBoxDimensionsString: `${scaledBoxWidth}×${scaledBoxHeight}`,
|
||||
canvasCoordinatesString: `${roundToHundreth(stageX)}×${roundToHundreth(
|
||||
stageY
|
||||
)}`,
|
||||
canvasDimensionsString: `${stageWidth}×${stageHeight}`,
|
||||
canvasScaleString: Math.round(stageScale * 100),
|
||||
shouldShowCanvasDebugInfo,
|
||||
shouldShowScaledBoundingBox: boundingBoxScaleMethod !== 'none',
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -52,6 +59,8 @@ const IAICanvasStatusText = () => {
|
||||
boundingBoxColor,
|
||||
boundingBoxCoordinatesString,
|
||||
boundingBoxDimensionsString,
|
||||
scaledBoundingBoxDimensionsString,
|
||||
shouldShowScaledBoundingBox,
|
||||
canvasCoordinatesString,
|
||||
canvasDimensionsString,
|
||||
canvasScaleString,
|
||||
@ -71,6 +80,13 @@ const IAICanvasStatusText = () => {
|
||||
color: boundingBoxColor,
|
||||
}}
|
||||
>{`Bounding Box: ${boundingBoxDimensionsString}`}</div>
|
||||
{shouldShowScaledBoundingBox && (
|
||||
<div
|
||||
style={{
|
||||
color: boundingBoxColor,
|
||||
}}
|
||||
>{`Scaled Bounding Box: ${scaledBoundingBoxDimensionsString}`}</div>
|
||||
)}
|
||||
{shouldShowCanvasDebugInfo && (
|
||||
<>
|
||||
<div>{`Bounding Box Position: ${boundingBoxCoordinatesString}`}</div>
|
||||
|
@ -18,6 +18,8 @@ import IAICheckbox from 'common/components/IAICheckbox';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import EmptyTempFolderButtonModal from 'features/system/components/ClearTempFolderButtonModal';
|
||||
import ClearCanvasHistoryButtonModal from '../ClearCanvasHistoryButtonModal';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
export const canvasControlsSelector = createSelector(
|
||||
[canvasSelector],
|
||||
@ -61,6 +63,21 @@ const IAICanvasSettingsButtonPopover = () => {
|
||||
shouldSnapToGrid,
|
||||
} = useAppSelector(canvasControlsSelector);
|
||||
|
||||
useHotkeys(
|
||||
['n'],
|
||||
() => {
|
||||
dispatch(setShouldSnapToGrid(!shouldSnapToGrid));
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
preventDefault: true,
|
||||
},
|
||||
[shouldSnapToGrid]
|
||||
);
|
||||
|
||||
const handleChangeShouldSnapToGrid = (e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldSnapToGrid(e.target.checked));
|
||||
|
||||
return (
|
||||
<IAIPopover
|
||||
trigger="hover"
|
||||
@ -88,7 +105,7 @@ const IAICanvasSettingsButtonPopover = () => {
|
||||
<IAICheckbox
|
||||
label="Snap to Grid"
|
||||
isChecked={shouldSnapToGrid}
|
||||
onChange={(e) => dispatch(setShouldSnapToGrid(e.target.checked))}
|
||||
onChange={handleChangeShouldSnapToGrid}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label="Darken Outside Selection"
|
||||
|
@ -14,6 +14,7 @@ import { STAGE_PADDING_PERCENTAGE } from '../util/constants';
|
||||
import floorCoordinates from '../util/floorCoordinates';
|
||||
import roundDimensionsTo64 from '../util/roundDimensionsTo64';
|
||||
import {
|
||||
BoundingBoxScale,
|
||||
CanvasImage,
|
||||
CanvasLayer,
|
||||
CanvasLayerState,
|
||||
@ -41,6 +42,7 @@ const initialCanvasState: CanvasState = {
|
||||
boundingBoxCoordinates: { x: 0, y: 0 },
|
||||
boundingBoxDimensions: { width: 512, height: 512 },
|
||||
boundingBoxPreviewFill: { r: 0, g: 0, b: 0, a: 0.5 },
|
||||
boundingBoxScaleMethod: 'auto',
|
||||
brushColor: { r: 90, g: 90, b: 255, a: 1 },
|
||||
brushSize: 50,
|
||||
canvasContainerDimensions: { width: 0, height: 0 },
|
||||
@ -70,7 +72,6 @@ const initialCanvasState: CanvasState = {
|
||||
shouldDarkenOutsideBoundingBox: false,
|
||||
shouldLockBoundingBox: false,
|
||||
shouldPreserveMaskedArea: false,
|
||||
shouldScaleBoundingBox: false,
|
||||
shouldShowBoundingBox: true,
|
||||
shouldShowBrush: true,
|
||||
shouldShowBrushPreview: false,
|
||||
@ -242,7 +243,43 @@ export const canvasSlice = createSlice({
|
||||
};
|
||||
},
|
||||
setBoundingBoxDimensions: (state, action: PayloadAction<Dimensions>) => {
|
||||
state.boundingBoxDimensions = roundDimensionsTo64(action.payload);
|
||||
const newDimensions = roundDimensionsTo64(action.payload);
|
||||
state.boundingBoxDimensions = newDimensions;
|
||||
|
||||
if (state.boundingBoxScaleMethod === 'auto') {
|
||||
const { width, height } = newDimensions;
|
||||
const newScaledDimensions = { width, height };
|
||||
const targetArea = 512 * 512;
|
||||
const aspectRatio = width / height;
|
||||
let currentArea = width * height;
|
||||
let maxDimension = 448;
|
||||
while (currentArea < targetArea) {
|
||||
maxDimension += 64;
|
||||
if (width === height) {
|
||||
newScaledDimensions.width = 512;
|
||||
newScaledDimensions.height = 512;
|
||||
break;
|
||||
} else {
|
||||
if (aspectRatio > 1) {
|
||||
newScaledDimensions.width = maxDimension;
|
||||
newScaledDimensions.height = roundToMultiple(
|
||||
maxDimension / aspectRatio,
|
||||
64
|
||||
);
|
||||
} else if (aspectRatio < 1) {
|
||||
newScaledDimensions.height = maxDimension;
|
||||
newScaledDimensions.width = roundToMultiple(
|
||||
maxDimension * aspectRatio,
|
||||
64
|
||||
);
|
||||
}
|
||||
currentArea =
|
||||
newScaledDimensions.width * newScaledDimensions.height;
|
||||
}
|
||||
}
|
||||
|
||||
state.scaledBoundingBoxDimensions = newScaledDimensions;
|
||||
}
|
||||
},
|
||||
setBoundingBoxCoordinates: (state, action: PayloadAction<Vector2d>) => {
|
||||
state.boundingBoxCoordinates = floorCoordinates(action.payload);
|
||||
@ -671,8 +708,11 @@ export const canvasSlice = createSlice({
|
||||
state.boundingBoxCoordinates = newBoundingBoxCoordinates;
|
||||
}
|
||||
},
|
||||
setShouldScaleBoundingBox: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldScaleBoundingBox = action.payload;
|
||||
setBoundingBoxScaleMethod: (
|
||||
state,
|
||||
action: PayloadAction<BoundingBoxScale>
|
||||
) => {
|
||||
state.boundingBoxScaleMethod = action.payload;
|
||||
},
|
||||
setScaledBoundingBoxDimensions: (
|
||||
state,
|
||||
@ -748,6 +788,7 @@ export const {
|
||||
setBoundingBoxCoordinates,
|
||||
setBoundingBoxDimensions,
|
||||
setBoundingBoxPreviewFill,
|
||||
setBoundingBoxScaleMethod,
|
||||
setBrushColor,
|
||||
setBrushSize,
|
||||
setCanvasContainerDimensions,
|
||||
@ -772,7 +813,6 @@ export const {
|
||||
setShouldDarkenOutsideBoundingBox,
|
||||
setShouldLockBoundingBox,
|
||||
setShouldPreserveMaskedArea,
|
||||
setShouldScaleBoundingBox,
|
||||
setShouldShowBoundingBox,
|
||||
setShouldShowBrush,
|
||||
setShouldShowBrushPreview,
|
||||
|
@ -11,6 +11,16 @@ export const LAYER_NAMES = ['base', 'mask'] as const;
|
||||
|
||||
export type CanvasLayer = typeof LAYER_NAMES[number];
|
||||
|
||||
export const BOUNDING_BOX_SCALES_DICT = [
|
||||
{ key: 'Auto', value: 'auto' },
|
||||
{ key: 'Manual', value: 'manual' },
|
||||
{ key: 'None', value: 'none' },
|
||||
];
|
||||
|
||||
export const BOUNDING_BOX_SCALES = ['none', 'auto', 'manual'] as const;
|
||||
|
||||
export type BoundingBoxScale = typeof BOUNDING_BOX_SCALES[number];
|
||||
|
||||
export type CanvasDrawingTool = 'brush' | 'eraser';
|
||||
|
||||
export type CanvasTool = CanvasDrawingTool | 'move' | 'colorPicker';
|
||||
@ -78,6 +88,7 @@ export interface CanvasState {
|
||||
boundingBoxCoordinates: Vector2d;
|
||||
boundingBoxDimensions: Dimensions;
|
||||
boundingBoxPreviewFill: RgbaColor;
|
||||
boundingBoxScaleMethod: BoundingBoxScale;
|
||||
brushColor: RgbaColor;
|
||||
brushSize: number;
|
||||
canvasContainerDimensions: Dimensions;
|
||||
@ -108,7 +119,6 @@ export interface CanvasState {
|
||||
shouldDarkenOutsideBoundingBox: boolean;
|
||||
shouldLockBoundingBox: boolean;
|
||||
shouldPreserveMaskedArea: boolean;
|
||||
shouldScaleBoundingBox: boolean;
|
||||
shouldShowBoundingBox: boolean;
|
||||
shouldShowBrush: boolean;
|
||||
shouldShowBrushPreview: boolean;
|
||||
|
@ -2,27 +2,17 @@ import { Box, Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import IAISwitch from 'common/components/IAISwitch';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
setBoundingBoxDimensions,
|
||||
setScaledBoundingBoxDimensions,
|
||||
setShouldScaleBoundingBox,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||
import _ from 'lodash';
|
||||
|
||||
const selector = createSelector(
|
||||
canvasSelector,
|
||||
(canvas) => {
|
||||
const {
|
||||
boundingBoxDimensions,
|
||||
shouldScaleBoundingBox,
|
||||
scaledBoundingBoxDimensions,
|
||||
} = canvas;
|
||||
const { boundingBoxDimensions, boundingBoxScaleMethod: boundingBoxScale } = canvas;
|
||||
return {
|
||||
boundingBoxDimensions,
|
||||
shouldScaleBoundingBox,
|
||||
scaledBoundingBoxDimensions,
|
||||
boundingBoxScale,
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -34,11 +24,7 @@ const selector = createSelector(
|
||||
|
||||
const BoundingBoxSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
boundingBoxDimensions,
|
||||
shouldScaleBoundingBox,
|
||||
scaledBoundingBoxDimensions,
|
||||
} = useAppSelector(selector);
|
||||
const { boundingBoxDimensions } = useAppSelector(selector);
|
||||
|
||||
const handleChangeWidth = (v: number) => {
|
||||
dispatch(
|
||||
@ -76,42 +62,6 @@ const BoundingBoxSettings = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const handleChangeScaledWidth = (v: number) => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
width: Math.floor(v),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleChangeScaledHeight = (v: number) => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
height: Math.floor(v),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResetScaledWidth = () => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
width: Math.floor(512),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResetScaledHeight = () => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
height: Math.floor(512),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<IAISlider
|
||||
@ -140,43 +90,6 @@ const BoundingBoxSettings = () => {
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
<IAISwitch
|
||||
label={'Scale Image Before Processing'}
|
||||
isChecked={shouldScaleBoundingBox}
|
||||
onChange={(e) => dispatch(setShouldScaleBoundingBox(e.target.checked))}
|
||||
/>
|
||||
<IAISlider
|
||||
isInputDisabled={!shouldScaleBoundingBox}
|
||||
isResetDisabled={!shouldScaleBoundingBox}
|
||||
isSliderDisabled={!shouldScaleBoundingBox}
|
||||
label={'Scaled W'}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
value={scaledBoundingBoxDimensions.width}
|
||||
onChange={handleChangeScaledWidth}
|
||||
handleReset={handleResetScaledWidth}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
<IAISlider
|
||||
isInputDisabled={!shouldScaleBoundingBox}
|
||||
isResetDisabled={!shouldScaleBoundingBox}
|
||||
isSliderDisabled={!shouldScaleBoundingBox}
|
||||
label={'Scaled H'}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
value={scaledBoundingBoxDimensions.height}
|
||||
onChange={handleChangeScaledHeight}
|
||||
handleReset={handleResetScaledHeight}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,182 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import {
|
||||
setBoundingBoxDimensions,
|
||||
setBoundingBoxScaleMethod,
|
||||
setScaledBoundingBoxDimensions,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
import {
|
||||
BoundingBoxScale,
|
||||
BOUNDING_BOX_SCALES_DICT,
|
||||
} from 'features/canvas/store/canvasTypes';
|
||||
import { optionsSelector } from 'features/options/store/optionsSelectors';
|
||||
import {
|
||||
setInfillMethod,
|
||||
setTileSize,
|
||||
} from 'features/options/store/optionsSlice';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import _ from 'lodash';
|
||||
import { ChangeEvent } from 'react';
|
||||
import InpaintReplace from './InpaintReplace';
|
||||
|
||||
const selector = createSelector(
|
||||
[optionsSelector, systemSelector, canvasSelector],
|
||||
(options, system, canvas) => {
|
||||
const { tileSize, infillMethod } = options;
|
||||
|
||||
const { infill_methods: availableInfillMethods } = system;
|
||||
|
||||
const {
|
||||
boundingBoxDimensions,
|
||||
boundingBoxScaleMethod: boundingBoxScale,
|
||||
scaledBoundingBoxDimensions,
|
||||
} = canvas;
|
||||
|
||||
return {
|
||||
boundingBoxDimensions,
|
||||
boundingBoxScale,
|
||||
scaledBoundingBoxDimensions,
|
||||
tileSize,
|
||||
infillMethod,
|
||||
availableInfillMethods,
|
||||
isManual: boundingBoxScale === 'manual',
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: _.isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const InfillAndScalingOptions = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
tileSize,
|
||||
infillMethod,
|
||||
boundingBoxDimensions,
|
||||
availableInfillMethods,
|
||||
boundingBoxScale,
|
||||
isManual,
|
||||
scaledBoundingBoxDimensions,
|
||||
} = useAppSelector(selector);
|
||||
|
||||
const handleChangeScaledWidth = (v: number) => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
width: Math.floor(v),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleChangeScaledHeight = (v: number) => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
height: Math.floor(v),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResetScaledWidth = () => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
width: Math.floor(512),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResetScaledHeight = () => {
|
||||
dispatch(
|
||||
setScaledBoundingBoxDimensions({
|
||||
...scaledBoundingBoxDimensions,
|
||||
height: Math.floor(512),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleChangeBoundingBoxScaleMethod = (
|
||||
e: ChangeEvent<HTMLSelectElement>
|
||||
) => {
|
||||
dispatch(setBoundingBoxScaleMethod(e.target.value as BoundingBoxScale));
|
||||
dispatch(setBoundingBoxDimensions(boundingBoxDimensions));
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<IAISelect
|
||||
label={'Scale Before Processing'}
|
||||
validValues={BOUNDING_BOX_SCALES_DICT}
|
||||
value={boundingBoxScale}
|
||||
onChange={handleChangeBoundingBoxScaleMethod}
|
||||
/>
|
||||
<IAISlider
|
||||
isInputDisabled={!isManual}
|
||||
isResetDisabled={!isManual}
|
||||
isSliderDisabled={!isManual}
|
||||
label={'Scaled W'}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
value={scaledBoundingBoxDimensions.width}
|
||||
onChange={handleChangeScaledWidth}
|
||||
handleReset={handleResetScaledWidth}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
<IAISlider
|
||||
isInputDisabled={!isManual}
|
||||
isResetDisabled={!isManual}
|
||||
isSliderDisabled={!isManual}
|
||||
label={'Scaled H'}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
value={scaledBoundingBoxDimensions.height}
|
||||
onChange={handleChangeScaledHeight}
|
||||
handleReset={handleResetScaledHeight}
|
||||
sliderNumberInputProps={{ max: 4096 }}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
/>
|
||||
<InpaintReplace />
|
||||
<IAISelect
|
||||
label="Infill Method"
|
||||
value={infillMethod}
|
||||
validValues={availableInfillMethods}
|
||||
onChange={(e) => dispatch(setInfillMethod(e.target.value))}
|
||||
/>
|
||||
<IAISlider
|
||||
isInputDisabled={infillMethod !== 'tile'}
|
||||
isResetDisabled={infillMethod !== 'tile'}
|
||||
isSliderDisabled={infillMethod !== 'tile'}
|
||||
sliderMarkRightOffset={-4}
|
||||
label={'Tile Size'}
|
||||
min={16}
|
||||
max={64}
|
||||
sliderNumberInputProps={{ max: 256 }}
|
||||
value={tileSize}
|
||||
onChange={(v) => {
|
||||
dispatch(setTileSize(v));
|
||||
}}
|
||||
handleReset={() => {
|
||||
dispatch(setTileSize(32));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default InfillAndScalingOptions;
|
@ -1,43 +1,26 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { optionsSelector } from 'features/options/store/optionsSelectors';
|
||||
import {
|
||||
setInfillMethod,
|
||||
setSeamBlur,
|
||||
setSeamSize,
|
||||
setSeamSteps,
|
||||
setSeamStrength,
|
||||
setTileSize,
|
||||
} from 'features/options/store/optionsSlice';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import _ from 'lodash';
|
||||
import InpaintReplace from './InpaintReplace';
|
||||
|
||||
const selector = createSelector(
|
||||
[optionsSelector, systemSelector],
|
||||
(options, system) => {
|
||||
const {
|
||||
seamSize,
|
||||
seamBlur,
|
||||
seamStrength,
|
||||
seamSteps,
|
||||
tileSize,
|
||||
infillMethod,
|
||||
} = options;
|
||||
|
||||
const { infill_methods: availableInfillMethods } = system;
|
||||
[optionsSelector],
|
||||
(options) => {
|
||||
const { seamSize, seamBlur, seamStrength, seamSteps } = options;
|
||||
|
||||
return {
|
||||
seamSize,
|
||||
seamBlur,
|
||||
seamStrength,
|
||||
seamSteps,
|
||||
tileSize,
|
||||
infillMethod,
|
||||
availableInfillMethods,
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -47,22 +30,13 @@ const selector = createSelector(
|
||||
}
|
||||
);
|
||||
|
||||
const CompositionOptions = () => {
|
||||
const SeamCorrectionOptions = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
seamSize,
|
||||
seamBlur,
|
||||
seamStrength,
|
||||
seamSteps,
|
||||
tileSize,
|
||||
infillMethod,
|
||||
availableInfillMethods,
|
||||
} = useAppSelector(selector);
|
||||
const { seamSize, seamBlur, seamStrength, seamSteps } =
|
||||
useAppSelector(selector);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<InpaintReplace />
|
||||
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-6}
|
||||
label={'Seam Size'}
|
||||
@ -129,33 +103,8 @@ const CompositionOptions = () => {
|
||||
withSliderMarks
|
||||
withReset
|
||||
/>
|
||||
<IAISelect
|
||||
label="Infill Method"
|
||||
value={infillMethod}
|
||||
validValues={availableInfillMethods}
|
||||
onChange={(e) => dispatch(setInfillMethod(e.target.value))}
|
||||
/>
|
||||
{infillMethod === 'tile' && (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-4}
|
||||
label={'Tile Size'}
|
||||
min={16}
|
||||
max={64}
|
||||
sliderNumberInputProps={{ max: 256 }}
|
||||
value={tileSize}
|
||||
onChange={(v) => {
|
||||
dispatch(setTileSize(v));
|
||||
}}
|
||||
handleReset={() => {
|
||||
dispatch(setTileSize(32));
|
||||
}}
|
||||
withInput
|
||||
withSliderMarks
|
||||
withReset
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default CompositionOptions;
|
||||
export default SeamCorrectionOptions;
|
@ -178,14 +178,19 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
||||
desc: 'Selects the canvas color picker',
|
||||
hotkey: 'C',
|
||||
},
|
||||
{
|
||||
title: 'Toggle Snap',
|
||||
desc: 'Toggles Snap to Grid',
|
||||
hotkey: 'N',
|
||||
},
|
||||
{
|
||||
title: 'Quick Toggle Move',
|
||||
desc: 'Temporarily toggles Move mode',
|
||||
hotkey: 'Hold Space',
|
||||
},
|
||||
{
|
||||
title: 'Select Mask Layer',
|
||||
desc: 'Toggles mask layer',
|
||||
title: 'Toggle Layer',
|
||||
desc: 'Toggles mask/base layer selection',
|
||||
hotkey: 'Q',
|
||||
},
|
||||
{
|
||||
|
@ -1,8 +1,7 @@
|
||||
// import { Feature } from 'app/features';
|
||||
import { Feature } from 'app/features';
|
||||
import ImageToImageStrength from 'features/options/components/AdvancedOptions/ImageToImage/ImageToImageStrength';
|
||||
import BoundingBoxSettings from 'features/options/components/AdvancedOptions/Canvas/BoundingBoxSettings/BoundingBoxSettings';
|
||||
import CompositionOptions from 'features/options/components/AdvancedOptions/Canvas/CompositionOptions';
|
||||
import SeamCorrectionOptions from 'features/options/components/AdvancedOptions/Canvas/SeamCorrectionOptions';
|
||||
import SeedOptions from 'features/options/components/AdvancedOptions/Seed/SeedOptions';
|
||||
import GenerateVariationsToggle from 'features/options/components/AdvancedOptions/Variations/GenerateVariations';
|
||||
import VariationsOptions from 'features/options/components/AdvancedOptions/Variations/VariationsOptions';
|
||||
@ -11,6 +10,8 @@ import OptionsAccordion from 'features/options/components/OptionsAccordion';
|
||||
import ProcessButtons from 'features/options/components/ProcessButtons/ProcessButtons';
|
||||
import PromptInput from 'features/options/components/PromptInput/PromptInput';
|
||||
import InvokeOptionsPanel from 'features/tabs/components/InvokeOptionsPanel';
|
||||
import BoundingBoxSettings from 'features/options/components/AdvancedOptions/Canvas/BoundingBoxSettings/BoundingBoxSettings';
|
||||
import InfillAndScalingOptions from 'features/options/components/AdvancedOptions/Canvas/InfillAndScalingOptions';
|
||||
|
||||
export default function UnifiedCanvasPanel() {
|
||||
const unifiedCanvasAccordions = {
|
||||
@ -19,10 +20,15 @@ export default function UnifiedCanvasPanel() {
|
||||
feature: Feature.BOUNDING_BOX,
|
||||
content: <BoundingBoxSettings />,
|
||||
},
|
||||
composition: {
|
||||
header: 'Composition',
|
||||
feature: Feature.CANVAS_COMPOSITION,
|
||||
content: <CompositionOptions />,
|
||||
seamCorrection: {
|
||||
header: 'Seam Correction',
|
||||
feature: Feature.SEAM_CORRECTION,
|
||||
content: <SeamCorrectionOptions />,
|
||||
},
|
||||
infillAndScaling: {
|
||||
header: 'Infill and Scaling',
|
||||
feature: Feature.INFILL_AND_SCALING,
|
||||
content: <InfillAndScalingOptions />,
|
||||
},
|
||||
seed: {
|
||||
header: 'Seed',
|
||||
|
Loading…
Reference in New Issue
Block a user