diff --git a/frontend/src/app/features.ts b/frontend/src/app/features.ts index 361c8356dc..ade41a515f 100644 --- a/frontend/src/app/features.ts +++ b/frontend/src/app/features.ts @@ -13,6 +13,7 @@ export enum Feature { UPSCALE, FACE_CORRECTION, IMAGE_TO_IMAGE, + OUTPAINTING, } /** For each tooltip in the UI, the below feature definitions & props will pull relevant information into the tooltip. * @@ -59,4 +60,9 @@ export const FEATURES: Record = { href: 'link/to/docs/feature3.html', guideImage: 'asset/path.gif', }, + [Feature.OUTPAINTING]: { + text: '', // TODO + href: 'link/to/docs/feature3.html', + guideImage: 'asset/path.gif', + }, }; diff --git a/frontend/src/common/util/parameterTranslation.ts b/frontend/src/common/util/parameterTranslation.ts index b32764665d..24a94b0850 100644 --- a/frontend/src/common/util/parameterTranslation.ts +++ b/frontend/src/common/util/parameterTranslation.ts @@ -39,32 +39,38 @@ export const frontendToBackendParameters = ( } = config; const { - prompt, - iterations, - steps, cfgScale, - threshold, - perlin, + codeformerFidelity, + facetoolStrength, + facetoolType, height, - width, - sampler, - seed, - seamless, hiresFix, img2imgStrength, initialImage, - shouldFitToWidthHeight, - shouldGenerateVariations, - variationAmount, + iterations, + perlin, + prompt, + sampler, + seamBlur, + seamless, + seamSize, + seamSteps, + seamStrength, + seed, seedWeights, + shouldFitToWidthHeight, + shouldForceOutpaint, + shouldGenerateVariations, + shouldRandomizeSeed, shouldRunESRGAN, + shouldRunFacetool, + steps, + threshold, + tileSize, upscalingLevel, upscalingStrength, - shouldRunFacetool, - facetoolStrength, - codeformerFidelity, - facetoolType, - shouldRandomizeSeed, + variationAmount, + width, } = optionsState; const { @@ -178,12 +184,12 @@ export const frontendToBackendParameters = ( // TODO: The server metadata generation needs to be changed to fix this. generationParameters.progress_images = false; - generationParameters.seam_size = 96; - generationParameters.seam_blur = 16; - generationParameters.seam_strength = 0.7; - generationParameters.seam_steps = 10; - generationParameters.tile_size = 32; - generationParameters.force_outpaint = false; + generationParameters.seam_size = seamSize; + generationParameters.seam_blur = seamBlur; + generationParameters.seam_strength = seamStrength; + generationParameters.seam_steps = seamSteps; + generationParameters.tile_size = tileSize; + generationParameters.force_outpaint = shouldForceOutpaint; } if (shouldGenerateVariations) { diff --git a/frontend/src/features/options/components/AdvancedOptions/Inpainting/OutpaintingOptions.tsx b/frontend/src/features/options/components/AdvancedOptions/Inpainting/OutpaintingOptions.tsx new file mode 100644 index 0000000000..88c0e1117d --- /dev/null +++ b/frontend/src/features/options/components/AdvancedOptions/Inpainting/OutpaintingOptions.tsx @@ -0,0 +1,143 @@ +import { 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 { optionsSelector } from 'features/options/store/optionsSelectors'; +import { + setSeamSize, + setSeamBlur, + setSeamStrength, + setSeamSteps, + setTileSize, + setShouldForceOutpaint, +} from 'features/options/store/optionsSlice'; + +const selector = createSelector([optionsSelector], (options) => { + const { + seamSize, + seamBlur, + seamStrength, + seamSteps, + tileSize, + shouldForceOutpaint, + } = options; + + return { + seamSize, + seamBlur, + seamStrength, + seamSteps, + tileSize, + shouldForceOutpaint, + }; +}); + +const OutpaintingOptions = () => { + const dispatch = useAppDispatch(); + const { + seamSize, + seamBlur, + seamStrength, + seamSteps, + tileSize, + shouldForceOutpaint, + } = useAppSelector(selector); + + return ( + + { + dispatch(setSeamSize(v)); + }} + handleReset={() => dispatch(setSeamSize(96))} + withInput + withSliderMarks + withReset + /> + { + dispatch(setSeamBlur(v)); + }} + handleReset={() => { + dispatch(setSeamBlur(16)); + }} + withInput + withSliderMarks + withReset + /> + { + dispatch(setSeamStrength(v)); + }} + handleReset={() => { + dispatch(setSeamStrength(0.7)); + }} + withInput + withSliderMarks + withReset + /> + { + dispatch(setSeamSteps(v)); + }} + handleReset={() => { + dispatch(setSeamSteps(10)); + }} + withInput + withSliderMarks + withReset + /> + { + dispatch(setTileSize(v)); + }} + handleReset={() => { + dispatch(setTileSize(32)); + }} + withInput + withSliderMarks + withReset + /> + { + dispatch(setShouldForceOutpaint(e.target.checked)); + }} + /> + + ); +}; + +export default OutpaintingOptions; diff --git a/frontend/src/features/options/components/AdvancedOptions/Inpainting/OutpaintingOptionsHeader.tsx b/frontend/src/features/options/components/AdvancedOptions/Inpainting/OutpaintingOptionsHeader.tsx new file mode 100644 index 0000000000..b2df8b13fb --- /dev/null +++ b/frontend/src/features/options/components/AdvancedOptions/Inpainting/OutpaintingOptionsHeader.tsx @@ -0,0 +1,11 @@ +import { Box } from '@chakra-ui/react'; + +const OutpaintingHeader = () => { + return ( + + Outpainting + + ); +}; + +export default OutpaintingHeader; diff --git a/frontend/src/features/options/store/optionsSlice.ts b/frontend/src/features/options/store/optionsSlice.ts index 6425d4968c..ac7bcd5388 100644 --- a/frontend/src/features/options/store/optionsSlice.ts +++ b/frontend/src/features/options/store/optionsSlice.ts @@ -11,84 +11,96 @@ export type UpscalingLevel = 2 | 4; export type FacetoolType = typeof FACETOOL_TYPES[number]; export interface OptionsState { - prompt: string; - iterations: number; - steps: number; - cfgScale: number; - height: number; - width: number; - sampler: string; - threshold: number; - perlin: number; - seed: number; - img2imgStrength: number; - facetoolType: FacetoolType; - facetoolStrength: number; - codeformerFidelity: number; - upscalingLevel: UpscalingLevel; - upscalingStrength: number; - initialImage?: InvokeAI.Image | string; // can be an Image or url - maskPath: string; - seamless: boolean; - hiresFix: boolean; - shouldFitToWidthHeight: boolean; - shouldGenerateVariations: boolean; - variationAmount: number; - seedWeights: string; - shouldRunESRGAN: boolean; - shouldRunFacetool: boolean; - shouldRandomizeSeed: boolean; - showAdvancedOptions: boolean; activeTab: number; - shouldShowImageDetails: boolean; - showDualDisplay: boolean; - shouldShowOptionsPanel: boolean; - shouldPinOptionsPanel: boolean; + cfgScale: number; + codeformerFidelity: number; + currentTheme: string; + facetoolStrength: number; + facetoolType: FacetoolType; + height: number; + hiresFix: boolean; + img2imgStrength: number; + initialImage?: InvokeAI.Image | string; // can be an Image or url + isLightBoxOpen: boolean; + iterations: number; + maskPath: string; optionsPanelScrollPosition: number; + perlin: number; + prompt: string; + sampler: string; + seamBlur: number; + seamless: boolean; + seamSize: number; + seamSteps: number; + seamStrength: number; + seed: number; + seedWeights: string; + shouldFitToWidthHeight: boolean; + shouldForceOutpaint: boolean; + shouldGenerateVariations: boolean; shouldHoldOptionsPanelOpen: boolean; shouldLoopback: boolean; - currentTheme: string; - isLightBoxOpen: boolean; + shouldPinOptionsPanel: boolean; + shouldRandomizeSeed: boolean; + shouldRunESRGAN: boolean; + shouldRunFacetool: boolean; + shouldShowImageDetails: boolean; + shouldShowOptionsPanel: boolean; + showAdvancedOptions: boolean; + showDualDisplay: boolean; + steps: number; + threshold: number; + tileSize: number; + upscalingLevel: UpscalingLevel; + upscalingStrength: number; + variationAmount: number; + width: number; } const initialOptionsState: OptionsState = { - prompt: '', - iterations: 1, - steps: 50, + activeTab: 0, cfgScale: 7.5, - height: 512, - width: 512, - sampler: 'k_lms', - threshold: 0, - perlin: 0, - seed: 0, - seamless: false, - hiresFix: false, - img2imgStrength: 0.75, - maskPath: '', - shouldFitToWidthHeight: true, - shouldGenerateVariations: false, - variationAmount: 0.1, - seedWeights: '', - shouldRunESRGAN: false, - upscalingLevel: 4, - upscalingStrength: 0.75, - shouldRunFacetool: false, + codeformerFidelity: 0.75, + currentTheme: 'dark', facetoolStrength: 0.8, facetoolType: 'gfpgan', - codeformerFidelity: 0.75, - shouldRandomizeSeed: true, - showAdvancedOptions: true, - activeTab: 0, - shouldShowImageDetails: false, - showDualDisplay: true, - shouldShowOptionsPanel: true, - shouldPinOptionsPanel: true, + height: 512, + hiresFix: false, + img2imgStrength: 0.75, + isLightBoxOpen: false, + iterations: 1, + maskPath: '', optionsPanelScrollPosition: 0, + perlin: 0, + prompt: '', + sampler: 'k_lms', + seamBlur: 16, + seamless: false, + seamSize: 96, + seamSteps: 10, + seamStrength: 0.7, + seed: 0, + seedWeights: '', + shouldFitToWidthHeight: true, + shouldForceOutpaint: false, + shouldGenerateVariations: false, shouldHoldOptionsPanelOpen: false, shouldLoopback: false, - currentTheme: 'dark', - isLightBoxOpen: false, + shouldPinOptionsPanel: true, + shouldRandomizeSeed: true, + shouldRunESRGAN: false, + shouldRunFacetool: false, + shouldShowImageDetails: false, + shouldShowOptionsPanel: true, + showAdvancedOptions: true, + showDualDisplay: true, + steps: 50, + threshold: 0, + tileSize: 32, + upscalingLevel: 4, + upscalingStrength: 0.75, + variationAmount: 0.1, + width: 512, }; const initialState: OptionsState = initialOptionsState; @@ -360,55 +372,79 @@ export const optionsSlice = createSlice({ setIsLightBoxOpen: (state, action: PayloadAction) => { state.isLightBoxOpen = action.payload; }, + setSeamSize: (state, action: PayloadAction) => { + state.seamSize = action.payload; + }, + setSeamBlur: (state, action: PayloadAction) => { + state.seamBlur = action.payload; + }, + setSeamStrength: (state, action: PayloadAction) => { + state.seamStrength = action.payload; + }, + setSeamSteps: (state, action: PayloadAction) => { + state.seamSteps = action.payload; + }, + setTileSize: (state, action: PayloadAction) => { + state.tileSize = action.payload; + }, + setShouldForceOutpaint: (state, action: PayloadAction) => { + state.shouldForceOutpaint = action.payload; + }, }, }); export const { - setPrompt, - setIterations, - setSteps, + clearInitialImage, + resetOptionsState, + resetSeed, + setActiveTab, + setAllImageToImageParameters, + setAllParameters, + setAllTextToImageParameters, setCfgScale, - setThreshold, - setPerlin, - setHeight, - setWidth, - setSampler, - setSeed, - setSeamless, - setHiresFix, - setImg2imgStrength, + setCodeformerFidelity, + setCurrentTheme, setFacetoolStrength, setFacetoolType, - setCodeformerFidelity, - setUpscalingLevel, - setUpscalingStrength, - setMaskPath, - resetSeed, - resetOptionsState, - setShouldFitToWidthHeight, - setParameter, - setShouldGenerateVariations, - setSeedWeights, - setVariationAmount, - setAllParameters, - setShouldRunFacetool, - setShouldRunESRGAN, - setShouldRandomizeSeed, - setShowAdvancedOptions, - setActiveTab, - setShouldShowImageDetails, - setAllTextToImageParameters, - setAllImageToImageParameters, - setShowDualDisplay, + setHeight, + setHiresFix, + setImg2imgStrength, setInitialImage, - clearInitialImage, - setShouldShowOptionsPanel, - setShouldPinOptionsPanel, + setIsLightBoxOpen, + setIterations, + setMaskPath, setOptionsPanelScrollPosition, + setParameter, + setPerlin, + setPrompt, + setSampler, + setSeamBlur, + setSeamless, + setSeamSize, + setSeamSteps, + setSeamStrength, + setSeed, + setSeedWeights, + setShouldFitToWidthHeight, + setShouldForceOutpaint, + setShouldGenerateVariations, setShouldHoldOptionsPanelOpen, setShouldLoopback, - setCurrentTheme, - setIsLightBoxOpen, + setShouldPinOptionsPanel, + setShouldRandomizeSeed, + setShouldRunESRGAN, + setShouldRunFacetool, + setShouldShowImageDetails, + setShouldShowOptionsPanel, + setShowAdvancedOptions, + setShowDualDisplay, + setSteps, + setThreshold, + setTileSize, + setUpscalingLevel, + setUpscalingStrength, + setVariationAmount, + setWidth, } = optionsSlice.actions; export default optionsSlice.reducer; diff --git a/frontend/src/features/system/store/systemSlice.ts b/frontend/src/features/system/store/systemSlice.ts index bdcd267c2f..13ba7c459e 100644 --- a/frontend/src/features/system/store/systemSlice.ts +++ b/frontend/src/features/system/store/systemSlice.ts @@ -59,7 +59,7 @@ const initialSystemState: SystemState = { isESRGANAvailable: true, socketId: '', shouldConfirmOnDelete: true, - openAccordions: [0], + openAccordions: [], currentStep: 0, totalSteps: 0, currentIteration: 0, diff --git a/frontend/src/features/tabs/components/UnifiedCanvas/UnifiedCanvasPanel.tsx b/frontend/src/features/tabs/components/UnifiedCanvas/UnifiedCanvasPanel.tsx index 41c8c598ce..7ab57687a0 100644 --- a/frontend/src/features/tabs/components/UnifiedCanvas/UnifiedCanvasPanel.tsx +++ b/frontend/src/features/tabs/components/UnifiedCanvas/UnifiedCanvasPanel.tsx @@ -5,6 +5,8 @@ import FaceRestoreHeader from 'features/options/components/AdvancedOptions/FaceR import FaceRestoreOptions from 'features/options/components/AdvancedOptions/FaceRestore/FaceRestoreOptions'; import ImageToImageStrength from 'features/options/components/AdvancedOptions/ImageToImage/ImageToImageStrength'; import InpaintingSettings from 'features/options/components/AdvancedOptions/Inpainting/InpaintingSettings'; +import OutpaintingOptions from 'features/options/components/AdvancedOptions/Inpainting/OutpaintingOptions'; +import OutpaintingHeader from 'features/options/components/AdvancedOptions/Inpainting/OutpaintingOptionsHeader'; import SeedHeader from 'features/options/components/AdvancedOptions/Seed/SeedHeader'; import SeedOptions from 'features/options/components/AdvancedOptions/Seed/SeedOptions'; import UpscaleHeader from 'features/options/components/AdvancedOptions/Upscale/UpscaleHeader'; @@ -24,6 +26,11 @@ export default function UnifiedCanvasPanel() { ); const imageToImageAccordions = { + outpainting: { + header: , + feature: Feature.OUTPAINTING, + options: , + }, seed: { header: , feature: Feature.SEED,