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
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Badge, Flex } from '@chakra-ui/react';
import { Image } from 'app/types/invokeai';
import { isNumber, isString } from 'lodash-es';
import { useMemo } from 'react';

type ImageMetadataOverlayProps = {
image: Image;
};

const ImageMetadataOverlay = ({ image }: ImageMetadataOverlayProps) => {
const dimensions = useMemo(() => {
if (!isNumber(image.metadata?.width) || isNumber(!image.metadata?.height)) {
return;
}

return `${image.metadata?.width} × ${image.metadata?.height}`;
}, [image.metadata]);

const model = useMemo(() => {
if (!isString(image.metadata?.invokeai?.node?.model)) {
return;
}

return image.metadata?.invokeai?.node?.model;
}, [image.metadata]);

return (
<Flex
sx={{
pointerEvents: 'none',
flexDirection: 'column',
position: 'absolute',
top: 0,
right: 0,
p: 2,
alignItems: 'flex-end',
gap: 2,
}}
>
{dimensions && (
<Badge variant="solid" colorScheme="base">
{dimensions}
</Badge>
)}
{model && (
<Badge variant="solid" colorScheme="base">
{model}
</Badge>
)}
</Flex>
);
};

export default ImageMetadataOverlay;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Flex, Image, Skeleton, useBoolean } from '@chakra-ui/react';
import { Box, Flex, Image } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { useGetUrl } from 'common/util/getUrl';
Expand All @@ -11,7 +11,8 @@ import NextPrevImageButtons from './NextPrevImageButtons';
import CurrentImageHidden from './CurrentImageHidden';
import { DragEvent, memo, useCallback } from 'react';
import { systemSelector } from 'features/system/store/systemSelectors';
import CurrentImageFallback from './CurrentImageFallback';
import ImageFallbackSpinner from './ImageFallbackSpinner';
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';

export const imagesSelector = createSelector(
[uiSelector, gallerySelector, systemSelector],
Expand Down Expand Up @@ -50,8 +51,6 @@ const CurrentImagePreview = () => {
} = useAppSelector(imagesSelector);
const { getUrl } = useGetUrl();

const [isLoaded, { on, off }] = useBoolean();

const handleDragStart = useCallback(
(e: DragEvent<HTMLDivElement>) => {
if (!image) {
Expand All @@ -67,11 +66,11 @@ const CurrentImagePreview = () => {
return (
<Flex
sx={{
position: 'relative',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%',
position: 'relative',
alignItems: 'center',
justifyContent: 'center',
}}
>
{progressImage && shouldShowProgressInViewer ? (
Expand All @@ -91,28 +90,23 @@ const CurrentImagePreview = () => {
/>
) : (
image && (
<Image
onDragStart={handleDragStart}
fallbackStrategy="beforeLoadOrError"
src={shouldHidePreview ? undefined : getUrl(image.url)}
width={image.metadata.width || 'auto'}
height={image.metadata.height || 'auto'}
fallback={
shouldHidePreview ? (
<CurrentImageHidden />
) : (
<CurrentImageFallback />
)
}
sx={{
objectFit: 'contain',
maxWidth: '100%',
maxHeight: '100%',
height: 'auto',
position: 'absolute',
borderRadius: 'base',
}}
/>
<>
<Image
src={getUrl(image.url)}
fallbackStrategy="beforeLoadOrError"
fallback={<ImageFallbackSpinner />}
onDragStart={handleDragStart}
sx={{
objectFit: 'contain',
maxWidth: '100%',
maxHeight: '100%',
height: 'auto',
position: 'absolute',
borderRadius: 'base',
}}
/>
<ImageMetadataOverlay image={image} />
</>
)
)}
{shouldShowImageDetails && image && 'metadata' in image && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Flex, Image } from '@chakra-ui/react';
import { Flex, Image, Spinner } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
Expand Down Expand Up @@ -42,6 +42,7 @@ const GalleryProgressImage = () => {
alignItems: 'center',
justifyContent: 'center',
aspectRatio: '1/1',
position: 'relative',
}}
>
<Image
Expand All @@ -61,6 +62,7 @@ const GalleryProgressImage = () => {
imageRendering: shouldAntialiasProgressImage ? 'auto' : 'pixelated',
}}
/>
<Spinner sx={{ position: 'absolute', top: 1, right: 1, opacity: 0.7 }} />
</Flex>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
h: 'full',
transition: 'transform 0.2s ease-out',
aspectRatio: '1/1',
cursor: 'pointer',
}}
>
<Image
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Flex, Spinner, SpinnerProps } from '@chakra-ui/react';

type CurrentImageFallbackProps = SpinnerProps;
type ImageFallbackSpinnerProps = SpinnerProps;

const CurrentImageFallback = (props: CurrentImageFallbackProps) => {
const ImageFallbackSpinner = (props: ImageFallbackSpinnerProps) => {
const { size = 'xl', ...rest } = props;

return (
Expand All @@ -21,4 +21,4 @@ const CurrentImageFallback = (props: CurrentImageFallbackProps) => {
);
};

export default CurrentImageFallback;
export default ImageFallbackSpinner;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { Image } from 'app/types/invokeai';
import { imageReceived, thumbnailReceived } from 'services/thunks/image';

type GalleryImageObjectFitType = 'contain' | 'cover';

Expand Down Expand Up @@ -63,6 +64,29 @@ export const gallerySlice = createSlice({
state.shouldUseSingleGalleryColumn = action.payload;
},
},
extraReducers(builder) {
builder.addCase(imageReceived.fulfilled, (state, action) => {
// When we get an updated URL for an image, we need to update the selectedImage in gallery,
// which is currently its own object (instead of a reference to an image in results/uploads)
const { imagePath } = action.payload;
const { imageName } = action.meta.arg;

if (state.selectedImage?.name === imageName) {
state.selectedImage.url = imagePath;
}
});

builder.addCase(thumbnailReceived.fulfilled, (state, action) => {
// When we get an updated URL for an image, we need to update the selectedImage in gallery,
// which is currently its own object (instead of a reference to an image in results/uploads)
const { thumbnailPath } = action.payload;
const { thumbnailName } = action.meta.arg;

if (state.selectedImage?.name === thumbnailName) {
state.selectedImage.thumbnail = thumbnailPath;
}
});
},
});

export const {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Flex, Image, Spinner } from '@chakra-ui/react';
import { Flex, Image } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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 { DragEvent, useCallback, useState } from 'react';
import { DragEvent, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { ImageType } from 'services/api';
import ImageToImageOverlay from 'common/components/ImageToImageOverlay';
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { initialImageSelected } from 'features/parameters/store/actions';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import ImageFallbackSpinner from 'features/gallery/components/ImageFallbackSpinner';

const selector = createSelector(
[generationSelector],
Expand All @@ -30,8 +31,6 @@ const InitialImagePreview = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();

const [isLoaded, setIsLoaded] = useState(false);

const onError = () => {
dispatch(
addToast({
Expand All @@ -42,13 +41,10 @@ const InitialImagePreview = () => {
})
);
dispatch(clearInitialImage());
setIsLoaded(false);
};

const handleDrop = useCallback(
(e: DragEvent<HTMLDivElement>) => {
setIsLoaded(false);

const name = e.dataTransfer.getData('invokeai/imageName');
const type = e.dataTransfer.getData('invokeai/imageType') as ImageType;

Expand All @@ -62,48 +58,32 @@ const InitialImagePreview = () => {
sx={{
width: 'full',
height: 'full',
position: 'relative',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
}}
onDrop={handleDrop}
>
<Flex
sx={{
height: 'full',
width: 'full',
blur: '5px',
position: 'relative',
alignItems: 'center',
justifyContent: 'center',
}}
>
{initialImage?.url && (
<>
<Image
sx={{
objectFit: 'contain',
borderRadius: 'base',
maxHeight: 'full',
}}
src={getUrl(initialImage?.url)}
onError={onError}
onLoad={() => {
setIsLoaded(true);
}}
fallback={
<Flex
sx={{ h: 36, alignItems: 'center', justifyContent: 'center' }}
>
<Spinner color="grey" w="5rem" h="5rem" />
</Flex>
}
/>
{isLoaded && <ImageToImageOverlay image={initialImage} />}
</>
)}
{!initialImage?.url && <SelectImagePlaceholder />}
</Flex>
{initialImage?.url && (
<>
<Image
src={getUrl(initialImage?.url)}
fallbackStrategy="beforeLoadOrError"
fallback={<ImageFallbackSpinner />}
onError={onError}
sx={{
objectFit: 'contain',
maxWidth: '100%',
maxHeight: '100%',
height: 'auto',
position: 'absolute',
borderRadius: 'base',
}}
/>
<ImageMetadataOverlay image={initialImage} />
</>
)}
{!initialImage?.url && <SelectImagePlaceholder />}
</Flex>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ export const systemSlice = createSlice({
state.currentStep = 0;
state.totalSteps = 0;
state.statusTranslationKey = 'common.statusConnected';
state.progressImage = null;

state.toastQueue.push(
makeToast({ title: t('toast.canceled'), status: 'warning' })
Expand Down