Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions invokeai/frontend/web/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,8 @@
"hidePreview": "Hide Preview",
"showPreview": "Show Preview",
"controlNetControlMode": "Control Mode",
"clipSkip": "Clip Skip"
"clipSkip": "Clip Skip",
"aspectRatio": "Ratio"
},
"settings": {
"models": "Models",
Expand Down Expand Up @@ -671,6 +672,7 @@
},
"ui": {
"showProgressImages": "Show Progress Images",
"hideProgressImages": "Hide Progress Images"
"hideProgressImages": "Hide Progress Images",
"swapSizes": "Swap Sizes"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ButtonGroup, Flex } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIButton from 'common/components/IAIButton';
import { setAspectRatio } from 'features/ui/store/uiSlice';

const aspectRatios = [
{ name: 'Free', value: null },
{ name: 'Portrait', value: 0.67 / 1 },
{ name: 'Wide', value: 16 / 9 },
{ name: 'Square', value: 1 / 1 },
];

export default function ParamAspectRatio() {
const aspectRatio = useAppSelector(
(state: RootState) => state.ui.aspectRatio
);

const dispatch = useAppDispatch();

return (
<Flex gap={2} flexGrow={1}>
<ButtonGroup isAttached>
{aspectRatios.map((ratio) => (
<IAIButton
key={ratio.name}
size="sm"
isChecked={aspectRatio === ratio.value}
onClick={() => dispatch(setAspectRatio(ratio.value))}
>
{ratio.name}
</IAIButton>
))}
</ButtonGroup>
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider';
import { roundToMultiple } from 'common/util/roundDownToMultiple';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { setHeight } from 'features/parameters/store/generationSlice';
import { setHeight, setWidth } from 'features/parameters/store/generationSlice';
import { configSelector } from 'features/system/store/configSelectors';
import { hotkeysSelector } from 'features/ui/store/hotkeysSlice';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';

const selector = createSelector(
[generationSelector, hotkeysSelector, configSelector],
(generation, hotkeys, config) => {
[generationSelector, hotkeysSelector, configSelector, uiSelector],
(generation, hotkeys, config, ui) => {
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
config.sd.height;
const { height } = generation;
const { aspectRatio } = ui;

const step = hotkeys.shift ? fineStep : coarseStep;

Expand All @@ -25,6 +28,7 @@ const selector = createSelector(
sliderMax,
inputMax,
step,
aspectRatio,
};
},
defaultSelectorOptions
Expand All @@ -36,21 +40,29 @@ type ParamHeightProps = Omit<
>;

const ParamHeight = (props: ParamHeightProps) => {
const { height, initial, min, sliderMax, inputMax, step } =
const { height, initial, min, sliderMax, inputMax, step, aspectRatio } =
useAppSelector(selector);
const dispatch = useAppDispatch();
const { t } = useTranslation();

const handleChange = useCallback(
(v: number) => {
dispatch(setHeight(v));
if (aspectRatio) {
const newWidth = roundToMultiple(v * aspectRatio, 8);
dispatch(setWidth(newWidth));
}
},
[dispatch]
[dispatch, aspectRatio]
);

const handleReset = useCallback(() => {
dispatch(setHeight(initial));
}, [dispatch, initial]);
if (aspectRatio) {
const newWidth = roundToMultiple(initial * aspectRatio, 8);
dispatch(setWidth(newWidth));
}
}, [dispatch, initial, aspectRatio]);

return (
<IAISlider
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Flex, Spacer, Text } from '@chakra-ui/react';
import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import { toggleSize } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
import { MdOutlineSwapVert } from 'react-icons/md';
import ParamAspectRatio from './ParamAspectRatio';
import ParamHeight from './ParamHeight';
import ParamWidth from './ParamWidth';

export default function ParamSize() {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const shouldFitToWidthHeight = useAppSelector(
(state: RootState) => state.generation.shouldFitToWidthHeight
);
return (
<Flex
sx={{
gap: 2,
p: 4,
borderRadius: 4,
flexDirection: 'column',
w: 'full',
bg: 'base.150',
_dark: {
bg: 'base.750',
},
}}
>
<Flex alignItems="center" gap={2}>
<Text
sx={{
fontSize: 'sm',
width: 'full',
color: 'base.700',
_dark: {
color: 'base.300',
},
}}
>
{t('parameters.aspectRatio')}
</Text>
<Spacer />
<ParamAspectRatio />
<IAIIconButton
tooltip={t('ui.swapSizes')}
aria-label={t('ui.swapSizes')}
size="sm"
icon={<MdOutlineSwapVert />}
fontSize={20}
onClick={() => dispatch(toggleSize())}
/>
</Flex>
<Flex gap={2} alignItems="center">
<Flex gap={2} flexDirection="column" width="full">
<ParamWidth isDisabled={!shouldFitToWidthHeight} />
<ParamHeight isDisabled={!shouldFitToWidthHeight} />
</Flex>
</Flex>
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider';
import { roundToMultiple } from 'common/util/roundDownToMultiple';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { setWidth } from 'features/parameters/store/generationSlice';
import { setHeight, setWidth } from 'features/parameters/store/generationSlice';
import { configSelector } from 'features/system/store/configSelectors';
import { hotkeysSelector } from 'features/ui/store/hotkeysSlice';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';

const selector = createSelector(
[generationSelector, hotkeysSelector, configSelector],
(generation, hotkeys, config) => {
[generationSelector, hotkeysSelector, configSelector, uiSelector],
(generation, hotkeys, config, ui) => {
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
config.sd.width;
const { width } = generation;
const { aspectRatio } = ui;

const step = hotkeys.shift ? fineStep : coarseStep;

Expand All @@ -25,6 +28,7 @@ const selector = createSelector(
sliderMax,
inputMax,
step,
aspectRatio,
};
},
defaultSelectorOptions
Expand All @@ -33,21 +37,29 @@ const selector = createSelector(
type ParamWidthProps = Omit<IAIFullSliderProps, 'label' | 'value' | 'onChange'>;

const ParamWidth = (props: ParamWidthProps) => {
const { width, initial, min, sliderMax, inputMax, step } =
const { width, initial, min, sliderMax, inputMax, step, aspectRatio } =
useAppSelector(selector);
const dispatch = useAppDispatch();
const { t } = useTranslation();

const handleChange = useCallback(
(v: number) => {
dispatch(setWidth(v));
if (aspectRatio) {
const newHeight = roundToMultiple(v / aspectRatio, 8);
dispatch(setHeight(newHeight));
}
},
[dispatch]
[dispatch, aspectRatio]
);

const handleReset = useCallback(() => {
dispatch(setWidth(initial));
}, [dispatch, initial]);
if (aspectRatio) {
const newHeight = roundToMultiple(initial / aspectRatio, 8);
dispatch(setHeight(newHeight));
}
}, [dispatch, initial, aspectRatio]);

return (
<IAISlider
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { DEFAULT_SCHEDULER_NAME } from 'app/constants';
import { roundToMultiple } from 'common/util/roundDownToMultiple';
import { configChanged } from 'features/system/store/configSlice';
import { setShouldShowAdvancedOptions } from 'features/ui/store/uiSlice';
import {
setAspectRatio,
setShouldShowAdvancedOptions,
} from 'features/ui/store/uiSlice';
import { clamp } from 'lodash-es';
import { ImageDTO } from 'services/api/types';
import { clipSkipMap } from '../components/Parameters/Advanced/ParamClipSkip';
Expand Down Expand Up @@ -139,6 +143,11 @@ export const generationSlice = createSlice({
setWidth: (state, action: PayloadAction<number>) => {
state.width = action.payload;
},
toggleSize: (state) => {
const [width, height] = [state.width, state.height];
state.width = height;
state.height = width;
},
setScheduler: (state, action: PayloadAction<SchedulerParam>) => {
state.scheduler = action.payload;
},
Expand Down Expand Up @@ -262,6 +271,12 @@ export const generationSlice = createSlice({
const advancedOptionsStatus = action.payload;
if (!advancedOptionsStatus) state.clipSkip = 0;
});
builder.addCase(setAspectRatio, (state, action) => {
const ratio = action.payload;
if (ratio) {
state.height = roundToMultiple(state.width / ratio, 8);
}
});
},
});

Expand All @@ -271,7 +286,9 @@ export const {
resetParametersState,
resetSeed,
setCfgScale,
setWidth,
setHeight,
toggleSize,
setImg2imgStrength,
setInfillMethod,
setIterations,
Expand All @@ -292,7 +309,6 @@ export const {
setThreshold,
setTileSize,
setVariationAmount,
setWidth,
setShouldUseSymmetry,
setHorizontalSymmetrySteps,
setVerticalSymmetrySteps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAICollapse from 'common/components/IAICollapse';
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
import ParamHeight from 'features/parameters/components/Parameters/Core/ParamHeight';
import ParamIterations from 'features/parameters/components/Parameters/Core/ParamIterations';
import ParamModelandVAEandScheduler from 'features/parameters/components/Parameters/Core/ParamModelandVAEandScheduler';
import ParamSize from 'features/parameters/components/Parameters/Core/ParamSize';
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
import ImageToImageFit from 'features/parameters/components/Parameters/ImageToImage/ImageToImageFit';
import ImageToImageStrength from 'features/parameters/components/Parameters/ImageToImage/ImageToImageStrength';
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
Expand Down Expand Up @@ -47,15 +46,14 @@ const ImageToImageTabCoreParameters = () => {
>
{shouldUseSliders ? (
<>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
<ParamWidth isDisabled={!shouldFitToWidthHeight} />
<ParamHeight isDisabled={!shouldFitToWidthHeight} />
<ParamSize />
</>
) : (
<>
Expand All @@ -68,8 +66,7 @@ const ImageToImageTabCoreParameters = () => {
<Box pt={2}>
<ParamSeedFull />
</Box>
<ParamWidth isDisabled={!shouldFitToWidthHeight} />
<ParamHeight isDisabled={!shouldFitToWidthHeight} />
<ParamSize />
</>
)}
<ImageToImageStrength />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAICollapse from 'common/components/IAICollapse';
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
import ParamHeight from 'features/parameters/components/Parameters/Core/ParamHeight';
import ParamIterations from 'features/parameters/components/Parameters/Core/ParamIterations';
import ParamModelandVAEandScheduler from 'features/parameters/components/Parameters/Core/ParamModelandVAEandScheduler';
import ParamSize from 'features/parameters/components/Parameters/Core/ParamSize';
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
import ParamSeedFull from 'features/parameters/components/Parameters/Seed/ParamSeedFull';
import { memo } from 'react';

Expand Down Expand Up @@ -43,15 +42,14 @@ const TextToImageTabCoreParameters = () => {
>
{shouldUseSliders ? (
<>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
<ParamModelandVAEandScheduler />
<Box pt={2}>
<ParamSeedFull />
</Box>
<ParamIterations />
<ParamSteps />
<ParamCFGScale />
<ParamWidth />
<ParamHeight />
<ParamSize />
</>
) : (
<>
Expand All @@ -64,8 +62,7 @@ const TextToImageTabCoreParameters = () => {
<Box pt={2}>
<ParamSeedFull />
</Box>
<ParamWidth />
<ParamHeight />
<ParamSize />
</>
)}
</Flex>
Expand Down
Loading