fix(ui): fix canvas img2img if no init image selected

This commit is contained in:
psychedelicious 2023-05-11 11:12:39 +10:00
parent f488b1a7f2
commit 8ef49c2640
7 changed files with 31 additions and 127 deletions

View File

@ -1,26 +1,20 @@
import { createSelector } from '@reduxjs/toolkit';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { validateSeedWeights } from 'common/util/seedWeightPairs';
import { initialCanvasImageSelector } from 'features/canvas/store/canvasSelectors';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { systemSelector } from 'features/system/store/systemSelectors';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { isEqual } from 'lodash-es';
export const readinessSelector = createSelector(
[
generationSelector,
systemSelector,
initialCanvasImageSelector,
activeTabNameSelector,
],
(generation, system) => {
[generationSelector, systemSelector, activeTabNameSelector],
(generation, system, activeTabName) => {
const {
prompt,
shouldGenerateVariations,
seedWeights,
initialImage,
seed,
isImageToImageEnabled,
} = generation;
const { isProcessing, isConnected } = system;
@ -34,7 +28,7 @@ export const readinessSelector = createSelector(
reasonsWhyNotReady.push('Missing prompt');
}
if (isImageToImageEnabled && !initialImage) {
if (activeTabName === 'img2img' && !initialImage) {
isReady = false;
reasonsWhyNotReady.push('No initial image selected');
}
@ -64,10 +58,5 @@ export const readinessSelector = createSelector(
// All good
return { isReady, reasonsWhyNotReady };
},
{
memoizeOptions: {
equalityCheck: isEqual,
resultEqualityCheck: isEqual,
},
}
defaultSelectorOptions
);

View File

@ -79,8 +79,6 @@ export const buildCanvasGraphAndBlobs = async (
moduleLog.debug(
{
data: {
// baseDataURL,
// maskDataURL,
baseIsPartiallyTransparent,
baseIsFullyTransparent,
doesMaskHaveBlackPixels,

View File

@ -5,8 +5,8 @@ import {
ImageToImageInvocation,
TextToImageInvocation,
} from 'services/api';
import { initialImageSelector } from 'features/parameters/store/generationSelectors';
import { O } from 'ts-toolbelt';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
export const buildImg2ImgNode = (
state: RootState,
@ -15,6 +15,8 @@ export const buildImg2ImgNode = (
const nodeId = uuidv4();
const { generation } = state;
const activeTabName = activeTabNameSelector(state);
const {
prompt,
negativePrompt,
@ -33,11 +35,6 @@ export const buildImg2ImgNode = (
// const initialImage = initialImageSelector(state);
if (!initialImage) {
// TODO: handle this
throw 'no initial image';
}
const imageToImageNode: ImageToImageInvocation = {
id: nodeId,
type: 'img2img',
@ -48,14 +45,23 @@ export const buildImg2ImgNode = (
cfg_scale: cfgScale,
scheduler: sampler as ImageToImageInvocation['scheduler'],
model,
image: {
image_name: initialImage.name,
image_type: initialImage.type,
},
strength,
fit,
};
// on Canvas tab, we do not manually specific init image
if (activeTabName === 'img2img') {
if (!initialImage) {
// TODO: handle this more better
throw 'no initial image';
}
imageToImageNode.image = {
image_name: initialImage.name,
image_type: initialImage.type,
};
}
if (!shouldRandomizeSeed) {
imageToImageNode.seed = seed;
}

View File

@ -1,5 +1,6 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISlider from 'common/components/IAISlider';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
@ -13,32 +14,25 @@ const selector = createSelector(
(generation, hotkeys, config) => {
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
config.sd.img2imgStrength;
const { img2imgStrength, isImageToImageEnabled } = generation;
const { img2imgStrength } = generation;
const step = hotkeys.shift ? fineStep : coarseStep;
return {
img2imgStrength,
isImageToImageEnabled,
initial,
min,
sliderMax,
inputMax,
step,
};
}
},
defaultSelectorOptions
);
const ImageToImageStrength = () => {
const {
img2imgStrength,
isImageToImageEnabled,
initial,
min,
sliderMax,
inputMax,
step,
} = useAppSelector(selector);
const { img2imgStrength, initial, min, sliderMax, inputMax, step } =
useAppSelector(selector);
const dispatch = useAppDispatch();
const { t } = useTranslation();
@ -64,7 +58,6 @@ const ImageToImageStrength = () => {
withInput
withSliderMarks
withReset
isDisabled={!isImageToImageEnabled}
sliderNumberInputProps={{ max: inputMax }}
/>
);

View File

@ -1,49 +0,0 @@
import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAISwitch from 'common/components/IAISwitch';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { uiSelector } from 'features/ui/store/uiSelectors';
import { shouldShowImageParametersChanged } from 'features/ui/store/uiSlice';
import { ChangeEvent } from 'react';
import { useTranslation } from 'react-i18next';
const selector = createSelector(
[uiSelector, generationSelector],
(ui, generation) => {
const { isImageToImageEnabled } = generation;
const { shouldShowImageParameters } = ui;
return {
isImageToImageEnabled,
shouldShowImageParameters,
};
},
defaultSelectorOptions
);
export default function ImageToImageToggle() {
const { shouldShowImageParameters } = useAppSelector(selector);
const { t } = useTranslation();
const dispatch = useAppDispatch();
const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
dispatch(shouldShowImageParametersChanged(e.target.checked));
return (
<Flex py={1.5} px={4} borderRadius={4}>
<IAISwitch
label={t('parameters.initialImage')}
isChecked={shouldShowImageParameters}
width="full"
onChange={handleChange}
justifyContent="space-between"
formLabelProps={{
fontWeight: 400,
}}
/>
</Flex>
);
}

View File

@ -5,28 +5,27 @@ import SelectImagePlaceholder from 'common/components/SelectImagePlaceholder';
import { useGetUrl } from 'common/util/getUrl';
import { clearInitialImage } from 'features/parameters/store/generationSlice';
import { addToast } from 'features/system/store/systemSlice';
import { isEqual } from 'lodash-es';
import { DragEvent, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ImageType } from 'services/api';
import ImageToImageOverlay from 'common/components/ImageToImageOverlay';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { initialImageSelected } from 'features/parameters/store/actions';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
const selector = createSelector(
[generationSelector],
(generation) => {
const { initialImage, isImageToImageEnabled } = generation;
const { initialImage } = generation;
return {
initialImage,
isImageToImageEnabled,
};
},
{ memoizeOptions: { resultEqualityCheck: isEqual } }
defaultSelectorOptions
);
const InitialImagePreview = () => {
const { initialImage, isImageToImageEnabled } = useAppSelector(selector);
const { initialImage } = useAppSelector(selector);
const { getUrl } = useGetUrl();
const dispatch = useAppDispatch();
const { t } = useTranslation();
@ -73,8 +72,6 @@ const InitialImagePreview = () => {
sx={{
height: 'full',
width: 'full',
opacity: isImageToImageEnabled ? 1 : 0.5,
filter: isImageToImageEnabled ? 'none' : 'auto',
blur: '5px',
position: 'relative',
alignItems: 'center',
@ -107,26 +104,6 @@ const InitialImagePreview = () => {
)}
{!initialImage?.url && <SelectImagePlaceholder />}
</Flex>
{/* {!isImageToImageEnabled && (
<Flex
sx={{
w: 'full',
h: 'full',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
}}
>
<Text
fontWeight={500}
fontSize="md"
userSelect="none"
color="base.200"
>
Image to Image is Disabled
</Text>
</Flex>
)} */}
</Flex>
);
};

View File

@ -35,7 +35,6 @@ export interface GenerationState {
shouldUseSymmetry: boolean;
horizontalSymmetrySteps: number;
verticalSymmetrySteps: number;
isImageToImageEnabled: boolean;
model: string;
shouldUseSeamless: boolean;
seamlessXAxis: boolean;
@ -71,7 +70,6 @@ export const initialGenerationState: GenerationState = {
shouldUseSymmetry: false,
horizontalSymmetrySteps: 0,
verticalSymmetrySteps: 0,
isImageToImageEnabled: false,
model: '',
shouldUseSeamless: false,
seamlessXAxis: true,
@ -233,10 +231,6 @@ export const generationSlice = createSlice({
},
initialImageChanged: (state, action: PayloadAction<InvokeAI.Image>) => {
state.initialImage = action.payload;
state.isImageToImageEnabled = true;
},
isImageToImageEnabledChanged: (state, action: PayloadAction<boolean>) => {
state.isImageToImageEnabled = action.payload;
},
modelSelected: (state, action: PayloadAction<string>) => {
state.model = action.payload;
@ -249,9 +243,6 @@ export const {
clearInitialImage,
resetParametersState,
resetSeed,
setAllImageToImageParameters,
setAllParameters,
setAllTextToImageParameters,
setCfgScale,
setHeight,
setImg2imgStrength,
@ -282,7 +273,6 @@ export const {
setHorizontalSymmetrySteps,
setVerticalSymmetrySteps,
initialImageChanged,
isImageToImageEnabledChanged,
modelSelected,
setShouldUseNoiseSettings,
setSeamless,