Skip to content

Commit f9d3966

Browse files
feat(ui): add scale param to upscaling tab
1 parent 7cee4e4 commit f9d3966

File tree

6 files changed

+74
-72
lines changed

6 files changed

+74
-72
lines changed

invokeai/frontend/web/public/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,11 +1649,13 @@
16491649
"structure": "Structure",
16501650
"toInstall": "to install",
16511651
"upscaleModel": "Upcale Model",
1652+
"scale": "Scale",
16521653
"visit": "Visit",
16531654
"warningNoMainModel": "a model",
16541655
"warningNoTile": "a {{base_model}} tile controlnet required by this feature",
16551656
"warningNoTileOrUpscaleModel": "an upscaler model and {{base_model}} tile controlnet required by this feature",
16561657
"warningNoUpscaleModel": "an upscaler model required by this feature",
1658+
"upscalingFromTo": "Upscaling from {{from}} to {{to}}"
16571659
},
16581660
"ui": {
16591661
"tabs": {

invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { RootState } from 'app/store/store';
22
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
33
import type { GraphType } from 'features/nodes/util/graph/generation/Graph';
44
import { Graph } from 'features/nodes/util/graph/generation/Graph';
5-
import type { ImageDTO } from 'services/api/types';
65
import { isNonRefinerMainModelConfig, isSpandrelImageToImageModelConfig } from 'services/api/types';
76
import { assert } from 'tsafe';
87

@@ -15,7 +14,6 @@ import {
1514
NEGATIVE_CONDITIONING,
1615
NOISE,
1716
POSITIVE_CONDITIONING,
18-
RESIZE,
1917
SDXL_MODEL_LOADER,
2018
SPANDREL,
2119
TILED_MULTI_DIFFUSION_DENOISE_LATENTS,
@@ -26,27 +24,17 @@ import { addLoRAs } from './generation/addLoRAs';
2624
import { addSDXLLoRas } from './generation/addSDXLLoRAs';
2725
import { getBoardField, getSDXLStylePrompts } from './graphBuilderUtils';
2826

29-
const UPSCALE_SCALE = 2;
30-
31-
export const getOutputImageSize = (initialImage: ImageDTO) => {
32-
return {
33-
width: ((initialImage.width * UPSCALE_SCALE) / 8) * 8,
34-
height: ((initialImage.height * UPSCALE_SCALE) / 8) * 8,
35-
};
36-
};
37-
3827
export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promise<GraphType> => {
3928
const { model, cfgScale: cfg_scale, scheduler, steps, vaePrecision, seed, vae } = state.generation;
4029
const { positivePrompt, negativePrompt } = state.controlLayers.present;
41-
const { upscaleModel, upscaleInitialImage, sharpness, structure, creativity, tileControlnetModel } = state.upscale;
30+
const { upscaleModel, upscaleInitialImage, sharpness, structure, creativity, tileControlnetModel, scale } =
31+
state.upscale;
4232

4333
assert(model, 'No model found in state');
4434
assert(upscaleModel, 'No upscale model found in state');
4535
assert(upscaleInitialImage, 'No initial image found in state');
4636
assert(tileControlnetModel, 'Tile controlnet is required');
4737

48-
const { width: outputWidth, height: outputHeight } = getOutputImageSize(upscaleInitialImage);
49-
5038
const g = new Graph();
5139

5240
const unsharpMaskNode1 = g.addNode({
@@ -61,7 +49,8 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
6149
id: SPANDREL,
6250
type: 'spandrel_image_to_image',
6351
image_to_image_model: upscaleModel,
64-
tile_size: 500,
52+
fit_to_multiple_of_8: true,
53+
scale,
6554
});
6655

6756
g.addEdge(unsharpMaskNode1, 'image', upscaleNode, 'image');
@@ -75,24 +64,14 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
7564

7665
g.addEdge(upscaleNode, 'image', unsharpMaskNode2, 'image');
7766

78-
const resizeNode = g.addNode({
79-
id: RESIZE,
80-
type: 'img_resize',
81-
width: outputWidth,
82-
height: outputHeight,
83-
resample_mode: 'lanczos',
84-
});
85-
86-
g.addEdge(unsharpMaskNode2, 'image', resizeNode, 'image');
87-
8867
const noiseNode = g.addNode({
8968
id: NOISE,
9069
type: 'noise',
9170
seed,
9271
});
9372

94-
g.addEdge(resizeNode, 'width', noiseNode, 'width');
95-
g.addEdge(resizeNode, 'height', noiseNode, 'height');
73+
g.addEdge(unsharpMaskNode2, 'width', noiseNode, 'width');
74+
g.addEdge(unsharpMaskNode2, 'height', noiseNode, 'height');
9675

9776
const i2lNode = g.addNode({
9877
id: IMAGE_TO_LATENTS,
@@ -101,7 +80,7 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
10180
tiled: true,
10281
});
10382

104-
g.addEdge(resizeNode, 'image', i2lNode, 'image');
83+
g.addEdge(unsharpMaskNode2, 'image', i2lNode, 'image');
10584

10685
const l2iNode = g.addNode({
10786
type: 'l2i',
@@ -160,8 +139,6 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
160139

161140
g.upsertMetadata({
162141
cfg_scale,
163-
height: outputHeight,
164-
width: outputWidth,
165142
positive_prompt: positivePrompt,
166143
negative_prompt: negativePrompt,
167144
positive_style_prompt: positiveStylePrompt,
@@ -204,8 +181,6 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
204181

205182
g.upsertMetadata({
206183
cfg_scale,
207-
height: outputHeight,
208-
width: outputWidth,
209184
positive_prompt: positivePrompt,
210185
negative_prompt: negativePrompt,
211186
model: Graph.getModelMetadataField(modelConfig),
@@ -221,6 +196,8 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
221196
}
222197

223198
g.setMetadataReceivingNode(l2iNode);
199+
g.addEdgeToMetadata(upscaleNode, 'width', 'width');
200+
g.addEdgeToMetadata(upscaleNode, 'height', 'height');
224201

225202
let vaeNode;
226203
if (vae) {
@@ -252,7 +229,7 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
252229
end_step_percent: (structure + 10) * 0.025 + 0.3,
253230
});
254231

255-
g.addEdge(resizeNode, 'image', controlnetNode1, 'image');
232+
g.addEdge(unsharpMaskNode2, 'image', controlnetNode1, 'image');
256233

257234
const controlnetNode2 = g.addNode({
258235
id: 'controlnet_2',
@@ -265,7 +242,7 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis
265242
end_step_percent: 0.85,
266243
});
267244

268-
g.addEdge(resizeNode, 'image', controlnetNode2, 'image');
245+
g.addEdge(unsharpMaskNode2, 'image', controlnetNode2, 'image');
269246

270247
const collectNode = g.addNode({
271248
id: CONTROL_NET_COLLECT,

invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface UpscaleState {
1212
structure: number;
1313
creativity: number;
1414
tileControlnetModel: ControlNetModelConfig | null;
15+
scale: number;
1516
}
1617

1718
const initialUpscaleState: UpscaleState = {
@@ -22,6 +23,7 @@ const initialUpscaleState: UpscaleState = {
2223
structure: 0,
2324
creativity: 0,
2425
tileControlnetModel: null,
26+
scale: 4,
2527
};
2628

2729
export const upscaleSlice = createSlice({
@@ -46,6 +48,9 @@ export const upscaleSlice = createSlice({
4648
tileControlnetModelChanged: (state, action: PayloadAction<ControlNetModelConfig | null>) => {
4749
state.tileControlnetModel = action.payload;
4850
},
51+
scaleChanged: (state, action: PayloadAction<number>) => {
52+
state.scale = action.payload;
53+
},
4954
},
5055
});
5156

@@ -56,6 +61,7 @@ export const {
5661
creativityChanged,
5762
sharpnessChanged,
5863
tileControlnetModelChanged,
64+
scaleChanged,
5965
} = upscaleSlice.actions;
6066

6167
export const selectUpscalelice = (state: RootState) => state.upscale;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
2+
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
3+
import { scaleChanged } from 'features/parameters/store/upscaleSlice';
4+
import { memo, useCallback } from 'react';
5+
import { useTranslation } from 'react-i18next';
6+
7+
const marks = [2, 4, 8, 16];
8+
9+
const formatValue = (val: number) => `${val}x`;
10+
11+
export const UpscaleScaleSlider = memo(() => {
12+
const dispatch = useAppDispatch();
13+
const { t } = useTranslation();
14+
const scale = useAppSelector((s) => s.upscale.scale);
15+
16+
const onChange = useCallback(
17+
(val: number) => {
18+
dispatch(scaleChanged(val));
19+
},
20+
[dispatch]
21+
);
22+
23+
return (
24+
<FormControl orientation="vertical" gap={0}>
25+
<FormLabel m={0}>{t('upscaling.scale')}</FormLabel>
26+
<CompositeSlider
27+
min={2}
28+
max={16}
29+
value={scale}
30+
onChange={onChange}
31+
marks={marks}
32+
formatValue={formatValue}
33+
withThumbTooltip
34+
/>
35+
</FormControl>
36+
);
37+
});
38+
39+
UpscaleScaleSlider.displayName = 'UpscaleScaleSlider';

invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,30 @@ import ParamSharpness from 'features/parameters/components/Upscale/ParamSharpnes
66
import ParamSpandrelModel from 'features/parameters/components/Upscale/ParamSpandrelModel';
77
import ParamStructure from 'features/parameters/components/Upscale/ParamStructure';
88
import { selectUpscalelice } from 'features/parameters/store/upscaleSlice';
9+
import { UpscaleScaleSlider } from 'features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider';
910
import { useExpanderToggle } from 'features/settingsAccordions/hooks/useExpanderToggle';
1011
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
1112
import { memo } from 'react';
1213
import { useTranslation } from 'react-i18next';
1314

1415
import { MultidiffusionWarning } from './MultidiffusionWarning';
1516
import { UpscaleInitialImage } from './UpscaleInitialImage';
16-
import { UpscaleSizeDetails } from './UpscaleSizeDetails';
1717

18-
const selector = createMemoizedSelector([selectUpscalelice], (upscale) => {
18+
const selector = createMemoizedSelector([selectUpscalelice], (upscaleSlice) => {
19+
const { upscaleModel, upscaleInitialImage, scale } = upscaleSlice;
20+
1921
const badges: string[] = [];
2022

21-
if (upscale.upscaleModel) {
22-
badges.push(upscale.upscaleModel.name);
23+
if (upscaleModel) {
24+
badges.push(upscaleModel.name);
25+
}
26+
27+
if (upscaleInitialImage) {
28+
// Output height and width are scaled and rounded down to the nearest multiple of 8
29+
const outputWidth = Math.floor((upscaleInitialImage.width * scale) / 8) * 8;
30+
const outputHeight = Math.floor((upscaleInitialImage.height * scale) / 8) * 8;
31+
32+
badges.push(`${outputWidth}×${outputHeight}`);
2333
}
2434

2535
return { badges };
@@ -43,9 +53,9 @@ export const UpscaleSettingsAccordion = memo(() => {
4353
<Flex pt={4} px={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion">
4454
<Flex gap={4}>
4555
<UpscaleInitialImage />
46-
<Flex direction="column" w="full" alignItems="center" gap={4}>
56+
<Flex direction="column" w="full" alignItems="center" gap={2}>
4757
<ParamSpandrelModel />
48-
<UpscaleSizeDetails />
58+
<UpscaleScaleSlider />
4959
<MultidiffusionWarning />
5060
</Flex>
5161
</Flex>

invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSizeDetails.tsx

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)