diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
index 90e554f7f9..0d363a6238 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
@@ -8,7 +8,10 @@ import IAIButton from 'common/components/IAIButton';
import IAIIconButton from 'common/components/IAIIconButton';
import IAIPopover from 'common/components/IAIPopover';
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
-import { GalleryState } from 'features/gallery/store/gallerySlice';
+import {
+ GalleryState,
+ setHiddenState,
+} from 'features/gallery/store/gallerySlice';
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
import { setIsLightboxOpen } from 'features/lightbox/store/lightboxSlice';
import FaceRestoreSettings from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings';
@@ -38,6 +41,8 @@ import {
FaDownload,
FaExpand,
FaExpandArrowsAlt,
+ FaEye,
+ FaEyeSlash,
FaGrinStars,
FaQuoteRight,
FaSeedling,
@@ -77,7 +82,7 @@ const currentImageButtonsSelector = createSelector(
const { shouldShowImageDetails } = ui;
- const { intermediateImage, currentImage } = gallery;
+ const { intermediateImage, currentImage, hidden } = gallery;
return {
isProcessing,
@@ -91,6 +96,7 @@ const currentImageButtonsSelector = createSelector(
shouldShowImageDetails,
activeTabName,
isLightboxOpen,
+ hidden,
};
},
{
@@ -120,6 +126,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
currentImage,
isLightboxOpen,
activeTabName,
+ hidden,
} = useAppSelector(currentImageButtonsSelector);
const toast = useToast();
@@ -188,6 +195,10 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
[currentImage]
);
+ const handleHiddenChange = () => {
+ dispatch(setHiddenState(!hidden));
+ };
+
const handleClickUseAllParameters = () => {
if (!currentImage) return;
currentImage.metadata && dispatch(setAllParameters(currentImage.metadata));
@@ -455,6 +466,17 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
+ : }
+ tooltip={
+ !hidden ? t('parameters.hidePreview') : t('parameters.showPreview')
+ }
+ aria-label={
+ !hidden ? t('parameters.hidePreview') : t('parameters.showPreview')
+ }
+ isChecked={hidden}
+ onClick={handleHiddenChange}
+ />
}
tooltip={
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImageHidden.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImageHidden.tsx
new file mode 100644
index 0000000000..2674f6a0ba
--- /dev/null
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImageHidden.tsx
@@ -0,0 +1,21 @@
+import { Flex } from '@chakra-ui/react';
+import { FaEyeSlash } from 'react-icons/fa';
+
+const CurrentImageHidden = () => {
+ return (
+
+
+
+ );
+};
+
+export default CurrentImageHidden;
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImagePreview.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImagePreview.tsx
index 76dc410b81..283e179ae5 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImagePreview.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImagePreview.tsx
@@ -10,17 +10,19 @@ import { gallerySelector } from '../store/gallerySelectors';
import CurrentImageFallback from './CurrentImageFallback';
import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer';
import NextPrevImageButtons from './NextPrevImageButtons';
+import CurrentImageHidden from './CurrentImageHidden';
export const imagesSelector = createSelector(
[gallerySelector, uiSelector],
(gallery: GalleryState, ui) => {
- const { currentImage, intermediateImage } = gallery;
+ const { currentImage, intermediateImage, hidden } = gallery;
const { shouldShowImageDetails } = ui;
return {
imageToDisplay: intermediateImage ? intermediateImage : currentImage,
isIntermediate: Boolean(intermediateImage),
shouldShowImageDetails,
+ hidden,
};
},
{
@@ -31,7 +33,7 @@ export const imagesSelector = createSelector(
);
export default function CurrentImagePreview() {
- const { shouldShowImageDetails, imageToDisplay, isIntermediate } =
+ const { shouldShowImageDetails, imageToDisplay, isIntermediate, hidden } =
useAppSelector(imagesSelector);
return (
@@ -46,10 +48,16 @@ export default function CurrentImagePreview() {
>
{imageToDisplay && (
: undefined}
+ fallback={
+ hidden ? (
+
+ ) : !isIntermediate ? (
+
+ ) : undefined
+ }
sx={{
objectFit: 'contain',
maxWidth: '100%',
diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts
index dbb173c74a..a78ba4cef4 100644
--- a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts
+++ b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts
@@ -39,6 +39,7 @@ export interface GalleryState {
currentCategory: GalleryCategory;
galleryWidth: number;
shouldUseSingleGalleryColumn: boolean;
+ hidden: boolean;
}
const initialState: GalleryState = {
@@ -63,6 +64,7 @@ const initialState: GalleryState = {
},
galleryWidth: 300,
shouldUseSingleGalleryColumn: false,
+ hidden: false,
};
export const gallerySlice = createSlice({
@@ -251,11 +253,15 @@ export const gallerySlice = createSlice({
) => {
state.shouldUseSingleGalleryColumn = action.payload;
},
+ setHiddenState: (state, action: PayloadAction) => {
+ state.hidden = action.payload;
+ },
},
});
export const {
addImage,
+ setHiddenState,
clearIntermediateImage,
removeImage,
setCurrentImage,
diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/InitImagePreview.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/InitImagePreview.tsx
index 9eb26129a7..69e1058a9e 100644
--- a/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/InitImagePreview.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/tabs/ImageToImage/InitImagePreview.tsx
@@ -2,6 +2,7 @@ import { Flex, Image, Text, useToast } from '@chakra-ui/react';
import { RootState } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import ImageUploaderIconButton from 'common/components/ImageUploaderIconButton';
+import CurrentImageHidden from 'features/gallery/components/CurrentImageHidden';
import { clearInitialImage } from 'features/parameters/store/generationSlice';
import { useTranslation } from 'react-i18next';
@@ -10,6 +11,8 @@ export default function InitImagePreview() {
(state: RootState) => state.generation.initialImage
);
+ const { hidden } = useAppSelector((state: RootState) => state.gallery);
+
const { t } = useTranslation();
const dispatch = useAppDispatch();
@@ -66,8 +69,13 @@ export default function InitImagePreview() {
position: 'absolute',
}}
src={
- typeof initialImage === 'string' ? initialImage : initialImage.url
+ hidden
+ ? undefined
+ : typeof initialImage === 'string'
+ ? initialImage
+ : initialImage.url
}
+ fallback={}
onError={alertMissingInitImage}
/>