Adds auto-scaling for inpaint size

This commit is contained in:
psychedelicious 2022-11-24 19:19:28 +11:00 committed by blessedcoolant
parent 46a5fd67ed
commit d4280bbaaa
12 changed files with 316 additions and 171 deletions

View File

@ -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',
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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