mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): rough out img2img on canvas
This commit is contained in:
parent
b8479c5fe2
commit
044a713dc9
@ -4,6 +4,7 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'
|
|||||||
import { parseify } from 'common/util/serialize';
|
import { parseify } from 'common/util/serialize';
|
||||||
import {
|
import {
|
||||||
caImageChanged,
|
caImageChanged,
|
||||||
|
iiImageChanged,
|
||||||
ipaImageChanged,
|
ipaImageChanged,
|
||||||
layerImageAdded,
|
layerImageAdded,
|
||||||
rgIPAdapterImageChanged,
|
rgIPAdapterImageChanged,
|
||||||
@ -110,6 +111,18 @@ export const addImageDroppedListener = (startAppListening: AppStartListening) =>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image dropped on Raster layer
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
overData.actionType === 'SET_INITIAL_IMAGE' &&
|
||||||
|
activeData.payloadType === 'IMAGE_DTO' &&
|
||||||
|
activeData.payload.imageDTO
|
||||||
|
) {
|
||||||
|
dispatch(iiImageChanged({ imageDTO: activeData.payload.imageDTO }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image dropped on node image field
|
* Image dropped on node image field
|
||||||
*/
|
*/
|
||||||
|
@ -4,6 +4,7 @@ import { useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { AddLayerButton } from 'features/controlLayers/components/AddLayerButton';
|
import { AddLayerButton } from 'features/controlLayers/components/AddLayerButton';
|
||||||
import { CanvasEntityList } from 'features/controlLayers/components/CanvasEntityList';
|
import { CanvasEntityList } from 'features/controlLayers/components/CanvasEntityList';
|
||||||
import { DeleteAllLayersButton } from 'features/controlLayers/components/DeleteAllLayersButton';
|
import { DeleteAllLayersButton } from 'features/controlLayers/components/DeleteAllLayersButton';
|
||||||
|
import { InitialImage } from 'features/controlLayers/components/InitialImage/InitialImage';
|
||||||
import { IM } from 'features/controlLayers/components/InpaintMask/IM';
|
import { IM } from 'features/controlLayers/components/InpaintMask/IM';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ export const ControlLayersPanelContent = memo(() => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
{isCanvasSessionActive && <IM />}
|
{isCanvasSessionActive && <IM />}
|
||||||
<CanvasEntityList />
|
<CanvasEntityList />
|
||||||
|
{!isCanvasSessionActive && <InitialImage />}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import { useDisclosure } from '@invoke-ai/ui-library';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { CanvasEntityContainer } from 'features/controlLayers/components/common/CanvasEntityContainer';
|
||||||
|
import { InitialImageHeader } from 'features/controlLayers/components/InitialImage/InitialImageHeader';
|
||||||
|
import { InitialImageSettings } from 'features/controlLayers/components/InitialImage/InitialImageSettings';
|
||||||
|
import { entitySelected } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
|
||||||
|
export const InitialImage = memo(() => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const isSelected = useAppSelector((s) => s.canvasV2.selectedEntityIdentifier?.id === 'initial_image');
|
||||||
|
const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true });
|
||||||
|
const onSelect = useCallback(() => {
|
||||||
|
dispatch(entitySelected({ id: 'initial_image', type: 'initial_image' }));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CanvasEntityContainer isSelected={isSelected} onSelect={onSelect}>
|
||||||
|
<InitialImageHeader onToggleVisibility={onToggle} />
|
||||||
|
{isOpen && <InitialImageSettings />}
|
||||||
|
</CanvasEntityContainer>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
InitialImage.displayName = 'InitialImage';
|
@ -0,0 +1,34 @@
|
|||||||
|
import { Spacer } from '@invoke-ai/ui-library';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { CanvasEntityEnabledToggle } from 'features/controlLayers/components/common/CanvasEntityEnabledToggle';
|
||||||
|
import { CanvasEntityHeader } from 'features/controlLayers/components/common/CanvasEntityHeader';
|
||||||
|
import { CanvasEntityTitle } from 'features/controlLayers/components/common/CanvasEntityTitle';
|
||||||
|
import { iiIsEnabledToggled } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
onToggleVisibility: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InitialImageHeader = memo(({ onToggleVisibility }: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const isEnabled = useAppSelector((s) => s.canvasV2.initialImage.isEnabled);
|
||||||
|
const onToggleIsEnabled = useCallback(() => {
|
||||||
|
dispatch(iiIsEnabledToggled());
|
||||||
|
}, [dispatch]);
|
||||||
|
const title = useMemo(() => {
|
||||||
|
return `${t('controlLayers.initialImage')}`;
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CanvasEntityHeader onToggle={onToggleVisibility}>
|
||||||
|
<CanvasEntityEnabledToggle isEnabled={isEnabled} onToggle={onToggleIsEnabled} />
|
||||||
|
<CanvasEntityTitle title={title} />
|
||||||
|
<Spacer />
|
||||||
|
</CanvasEntityHeader>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
InitialImageHeader.displayName = 'InitialImageHeader';
|
@ -0,0 +1,100 @@
|
|||||||
|
import { Flex, useShiftModifier } from '@invoke-ai/ui-library';
|
||||||
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
|
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||||
|
import { documentHeightChanged, documentWidthChanged, iiReset } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
|
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||||
|
import type { ImageDraggableData, InitialImageDropData } from 'features/dnd/types';
|
||||||
|
import { calculateNewSize } from 'features/parameters/components/DocumentSize/calculateNewSize';
|
||||||
|
import { memo, useCallback, useEffect, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { PiArrowCounterClockwiseBold, PiRulerBold } from 'react-icons/pi';
|
||||||
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
|
export const InitialImagePreview = memo(() => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const initialImage = useAppSelector((s) => s.canvasV2.initialImage);
|
||||||
|
const isConnected = useAppSelector((s) => s.system.isConnected);
|
||||||
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
|
const shift = useShiftModifier();
|
||||||
|
|
||||||
|
const { currentData: imageDTO, isError: isErrorControlImage } = useGetImageDTOQuery(
|
||||||
|
initialImage.imageObject?.image.name ?? skipToken
|
||||||
|
);
|
||||||
|
|
||||||
|
const onReset = useCallback(() => {
|
||||||
|
dispatch(iiReset());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
const onUseSize = useCallback(() => {
|
||||||
|
if (!imageDTO) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = { updateAspectRatio: true, clamp: true };
|
||||||
|
if (shift) {
|
||||||
|
const { width, height } = imageDTO;
|
||||||
|
dispatch(documentWidthChanged({ width, ...options }));
|
||||||
|
dispatch(documentHeightChanged({ height, ...options }));
|
||||||
|
} else {
|
||||||
|
const { width, height } = calculateNewSize(imageDTO.width / imageDTO.height, optimalDimension * optimalDimension);
|
||||||
|
dispatch(documentWidthChanged({ width, ...options }));
|
||||||
|
dispatch(documentHeightChanged({ height, ...options }));
|
||||||
|
}
|
||||||
|
}, [imageDTO, dispatch, optimalDimension, shift]);
|
||||||
|
|
||||||
|
const draggableData = useMemo<ImageDraggableData | undefined>(() => {
|
||||||
|
if (imageDTO) {
|
||||||
|
return {
|
||||||
|
id: 'initial_image',
|
||||||
|
payloadType: 'IMAGE_DTO',
|
||||||
|
payload: { imageDTO },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [imageDTO]);
|
||||||
|
|
||||||
|
const droppableData = useMemo<InitialImageDropData>(
|
||||||
|
() => ({ id: 'initial_image', actionType: 'SET_INITIAL_IMAGE' }),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isConnected && isErrorControlImage) {
|
||||||
|
onReset();
|
||||||
|
}
|
||||||
|
}, [onReset, isConnected, isErrorControlImage]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex w="full" alignItems="center" justifyContent="center">
|
||||||
|
<Flex position="relative" w="full" h="full" alignItems="center" justifyContent="center">
|
||||||
|
<IAIDndImage
|
||||||
|
draggableData={draggableData}
|
||||||
|
droppableData={droppableData}
|
||||||
|
imageDTO={imageDTO}
|
||||||
|
// postUploadAction={postUploadAction}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{imageDTO && (
|
||||||
|
<Flex position="absolute" flexDir="column" top={1} insetInlineEnd={1} gap={1}>
|
||||||
|
<IAIDndImageIcon
|
||||||
|
onClick={onReset}
|
||||||
|
icon={<PiArrowCounterClockwiseBold size={16} />}
|
||||||
|
tooltip={t('controlnet.resetControlImage')}
|
||||||
|
/>
|
||||||
|
<IAIDndImageIcon
|
||||||
|
onClick={onUseSize}
|
||||||
|
icon={<PiRulerBold size={16} />}
|
||||||
|
tooltip={
|
||||||
|
shift ? t('controlnet.setControlImageDimensionsForce') : t('controlnet.setControlImageDimensions')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
InitialImagePreview.displayName = 'InitialImagePreview';
|
@ -0,0 +1,13 @@
|
|||||||
|
import { CanvasEntitySettings } from 'features/controlLayers/components/common/CanvasEntitySettings';
|
||||||
|
import { InitialImagePreview } from 'features/controlLayers/components/InitialImage/InitialImagePreview';
|
||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
export const InitialImageSettings = memo(() => {
|
||||||
|
return (
|
||||||
|
<CanvasEntitySettings>
|
||||||
|
<InitialImagePreview />
|
||||||
|
</CanvasEntitySettings>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
InitialImageSettings.displayName = 'InitialImageSettings';
|
@ -0,0 +1,73 @@
|
|||||||
|
import { CanvasImage } from 'features/controlLayers/konva/CanvasImage';
|
||||||
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
|
import { getObjectGroupId } from 'features/controlLayers/konva/naming';
|
||||||
|
import type { InitialImageEntity } from 'features/controlLayers/store/types';
|
||||||
|
import Konva from 'konva';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
export class CanvasInitialImage {
|
||||||
|
id = 'initial_image';
|
||||||
|
manager: CanvasManager;
|
||||||
|
layer: Konva.Layer;
|
||||||
|
group: Konva.Group;
|
||||||
|
objectsGroup: Konva.Group;
|
||||||
|
image: CanvasImage | null;
|
||||||
|
private initialImageState: InitialImageEntity;
|
||||||
|
|
||||||
|
constructor(initialImageState: InitialImageEntity, manager: CanvasManager) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.layer = new Konva.Layer({
|
||||||
|
id: this.id,
|
||||||
|
imageSmoothingEnabled: true,
|
||||||
|
listening: false,
|
||||||
|
});
|
||||||
|
this.group = new Konva.Group({
|
||||||
|
id: getObjectGroupId(this.layer.id(), uuidv4()),
|
||||||
|
listening: false,
|
||||||
|
});
|
||||||
|
this.objectsGroup = new Konva.Group({ listening: false });
|
||||||
|
this.group.add(this.objectsGroup);
|
||||||
|
this.layer.add(this.group);
|
||||||
|
|
||||||
|
this.image = null;
|
||||||
|
this.initialImageState = initialImageState;
|
||||||
|
}
|
||||||
|
|
||||||
|
async render(initialImageState: InitialImageEntity) {
|
||||||
|
this.initialImageState = initialImageState;
|
||||||
|
|
||||||
|
if (!this.initialImageState.imageObject) {
|
||||||
|
this.layer.visible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageObject = this.initialImageState.imageObject;
|
||||||
|
|
||||||
|
if (!imageObject) {
|
||||||
|
if (this.image) {
|
||||||
|
this.image.konvaImageGroup.visible(false);
|
||||||
|
}
|
||||||
|
} else if (!this.image) {
|
||||||
|
this.image = await new CanvasImage(imageObject, {
|
||||||
|
onLoad: () => {
|
||||||
|
this.updateGroup();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.objectsGroup.add(this.image.konvaImageGroup);
|
||||||
|
await this.image.updateImageSource(imageObject.image.name);
|
||||||
|
} else if (!this.image.isLoading && !this.image.isError) {
|
||||||
|
await this.image.update(imageObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGroup() {
|
||||||
|
const visible = this.initialImageState ? this.initialImageState.isEnabled : false;
|
||||||
|
this.layer.visible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
this.layer.destroy();
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ import { assert } from 'tsafe';
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
export class CanvasInpaintMask {
|
export class CanvasInpaintMask {
|
||||||
id: string;
|
id = 'inpaint_mask';
|
||||||
manager: CanvasManager;
|
manager: CanvasManager;
|
||||||
layer: Konva.Layer;
|
layer: Konva.Layer;
|
||||||
group: Konva.Group;
|
group: Konva.Group;
|
||||||
@ -25,7 +25,6 @@ export class CanvasInpaintMask {
|
|||||||
private inpaintMaskState: InpaintMaskEntity;
|
private inpaintMaskState: InpaintMaskEntity;
|
||||||
|
|
||||||
constructor(entity: InpaintMaskEntity, manager: CanvasManager) {
|
constructor(entity: InpaintMaskEntity, manager: CanvasManager) {
|
||||||
this.id = 'inpaint_mask';
|
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.layer = new Konva.Layer({ id: this.id });
|
this.layer = new Konva.Layer({ id: this.id });
|
||||||
|
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
import type { Store } from '@reduxjs/toolkit';
|
import type { Store } from '@reduxjs/toolkit';
|
||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
|
import { CanvasInitialImage } from 'features/controlLayers/konva/CanvasInitialImage';
|
||||||
import {
|
import {
|
||||||
|
getCompositeLayerImage,
|
||||||
getControlAdapterImage,
|
getControlAdapterImage,
|
||||||
getGenerationMode,
|
getGenerationMode,
|
||||||
getImageSourceImage,
|
getInitialImage,
|
||||||
getInpaintMaskImage,
|
getInpaintMaskImage,
|
||||||
getRegionMaskImage,
|
getRegionMaskImage,
|
||||||
} from 'features/controlLayers/konva/util';
|
} from 'features/controlLayers/konva/util';
|
||||||
import { $lastProgressEvent, $shouldShowStagedImage } from 'features/controlLayers/store/canvasV2Slice';
|
import { $lastProgressEvent, $shouldShowStagedImage } from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import type { CanvasV2State } from 'features/controlLayers/store/types';
|
import type { CanvasV2State, GenerationMode } from 'features/controlLayers/store/types';
|
||||||
import type Konva from 'konva';
|
import type Konva from 'konva';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
import { getImageDTO as defaultGetImageDTO, uploadImage as defaultUploadImage } from 'services/api/endpoints/images';
|
import { getImageDTO as defaultGetImageDTO, uploadImage as defaultUploadImage } from 'services/api/endpoints/images';
|
||||||
@ -58,6 +60,7 @@ export class CanvasManager {
|
|||||||
layers: Map<string, CanvasLayer>;
|
layers: Map<string, CanvasLayer>;
|
||||||
regions: Map<string, CanvasRegion>;
|
regions: Map<string, CanvasRegion>;
|
||||||
inpaintMask: CanvasInpaintMask;
|
inpaintMask: CanvasInpaintMask;
|
||||||
|
initialImage: CanvasInitialImage;
|
||||||
util: Util;
|
util: Util;
|
||||||
stateApi: CanvasStateApi;
|
stateApi: CanvasStateApi;
|
||||||
preview: CanvasPreview;
|
preview: CanvasPreview;
|
||||||
@ -102,6 +105,13 @@ export class CanvasManager {
|
|||||||
this.layers = new Map();
|
this.layers = new Map();
|
||||||
this.regions = new Map();
|
this.regions = new Map();
|
||||||
this.controlAdapters = new Map();
|
this.controlAdapters = new Map();
|
||||||
|
|
||||||
|
this.initialImage = new CanvasInitialImage(this.stateApi.getInitialImageState(), this);
|
||||||
|
this.stage.add(this.initialImage.layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
async renderInitialImage() {
|
||||||
|
this.initialImage.render(this.stateApi.getInitialImageState());
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderLayers() {
|
async renderLayers() {
|
||||||
@ -180,6 +190,7 @@ export class CanvasManager {
|
|||||||
const regions = getRegionsState().entities;
|
const regions = getRegionsState().entities;
|
||||||
let zIndex = 0;
|
let zIndex = 0;
|
||||||
this.background.layer.zIndex(++zIndex);
|
this.background.layer.zIndex(++zIndex);
|
||||||
|
this.initialImage.layer.zIndex(++zIndex);
|
||||||
for (const layer of layers) {
|
for (const layer of layers) {
|
||||||
this.layers.get(layer.id)?.layer.zIndex(++zIndex);
|
this.layers.get(layer.id)?.layer.zIndex(++zIndex);
|
||||||
}
|
}
|
||||||
@ -225,6 +236,17 @@ export class CanvasManager {
|
|||||||
this.renderLayers();
|
this.renderLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.isFirstRender ||
|
||||||
|
state.initialImage !== this.prevState.initialImage ||
|
||||||
|
state.document !== this.prevState.document ||
|
||||||
|
state.tool.selected !== this.prevState.tool.selected ||
|
||||||
|
state.selectedEntityIdentifier?.id !== this.prevState.selectedEntityIdentifier?.id
|
||||||
|
) {
|
||||||
|
log.debug('Rendering intial image');
|
||||||
|
this.renderInitialImage();
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.isFirstRender ||
|
this.isFirstRender ||
|
||||||
state.regions.entities !== this.prevState.regions.entities ||
|
state.regions.entities !== this.prevState.regions.entities ||
|
||||||
@ -367,8 +389,19 @@ export class CanvasManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getGenerationMode() {
|
getGenerationMode(): GenerationMode {
|
||||||
return getGenerationMode({ manager: this });
|
const session = this.stateApi.getSession();
|
||||||
|
if (session.isActive) {
|
||||||
|
return getGenerationMode({ manager: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialImageState = this.stateApi.getInitialImageState();
|
||||||
|
|
||||||
|
if (initialImageState.imageObject && initialImageState.isEnabled) {
|
||||||
|
return 'img2img';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'txt2img';
|
||||||
}
|
}
|
||||||
|
|
||||||
getControlAdapterImage(arg: Omit<Parameters<typeof getControlAdapterImage>[0], 'manager'>) {
|
getControlAdapterImage(arg: Omit<Parameters<typeof getControlAdapterImage>[0], 'manager'>) {
|
||||||
@ -383,7 +416,11 @@ export class CanvasManager {
|
|||||||
return getInpaintMaskImage({ ...arg, manager: this });
|
return getInpaintMaskImage({ ...arg, manager: this });
|
||||||
}
|
}
|
||||||
|
|
||||||
getImageSourceImage(arg: Omit<Parameters<typeof getImageSourceImage>[0], 'manager'>) {
|
getInitialImage(arg: Omit<Parameters<typeof getCompositeLayerImage>[0], 'manager'>) {
|
||||||
return getImageSourceImage({ ...arg, manager: this });
|
if (this.stateApi.getSession().isActive) {
|
||||||
|
return getCompositeLayerImage({ ...arg, manager: this });
|
||||||
|
} else {
|
||||||
|
return getInitialImage({ ...arg, manager: this });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,9 @@ export class CanvasStateApi {
|
|||||||
getInpaintMaskState = () => {
|
getInpaintMaskState = () => {
|
||||||
return this.getState().inpaintMask;
|
return this.getState().inpaintMask;
|
||||||
};
|
};
|
||||||
|
getInitialImageState = () => {
|
||||||
|
return this.getState().initialImage;
|
||||||
|
};
|
||||||
getMaskOpacity = () => {
|
getMaskOpacity = () => {
|
||||||
return this.getState().settings.maskOpacity;
|
return this.getState().settings.maskOpacity;
|
||||||
};
|
};
|
||||||
|
@ -317,6 +317,23 @@ export function getControlAdapterLayerClone(arg: { manager: CanvasManager; id: s
|
|||||||
return controlAdapterClone;
|
return controlAdapterClone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getInitialImageLayerClone(arg: { manager: CanvasManager }): Konva.Layer {
|
||||||
|
const { manager } = arg;
|
||||||
|
|
||||||
|
const initialImage = manager.initialImage;
|
||||||
|
|
||||||
|
const initialImageClone = initialImage.layer.clone();
|
||||||
|
const objectGroupClone = initialImage.group.clone();
|
||||||
|
|
||||||
|
initialImageClone.destroyChildren();
|
||||||
|
initialImageClone.add(objectGroupClone);
|
||||||
|
|
||||||
|
objectGroupClone.opacity(1);
|
||||||
|
objectGroupClone.cache();
|
||||||
|
|
||||||
|
return initialImageClone;
|
||||||
|
}
|
||||||
|
|
||||||
export function getCompositeLayerStageClone(arg: { manager: CanvasManager }): Konva.Stage {
|
export function getCompositeLayerStageClone(arg: { manager: CanvasManager }): Konva.Stage {
|
||||||
const { manager } = arg;
|
const { manager } = arg;
|
||||||
|
|
||||||
@ -435,6 +452,34 @@ export async function getControlAdapterImage(arg: {
|
|||||||
return imageDTO;
|
return imageDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getInitialImage(arg: {
|
||||||
|
manager: CanvasManager;
|
||||||
|
bbox?: Rect;
|
||||||
|
preview?: boolean;
|
||||||
|
}): Promise<ImageDTO> {
|
||||||
|
const { manager, bbox, preview = false } = arg;
|
||||||
|
|
||||||
|
// if (region.imageCache) {
|
||||||
|
// const imageDTO = await this.util.getImageDTO(region.imageCache.name);
|
||||||
|
// if (imageDTO) {
|
||||||
|
// return imageDTO;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
const layerClone = getInitialImageLayerClone({ manager });
|
||||||
|
const blob = await konvaNodeToBlob(layerClone, bbox);
|
||||||
|
|
||||||
|
if (preview) {
|
||||||
|
previewBlob(blob, 'initial image');
|
||||||
|
}
|
||||||
|
|
||||||
|
layerClone.destroy();
|
||||||
|
|
||||||
|
const imageDTO = await manager.util.uploadImage(blob, 'initial_image.png', 'other', true);
|
||||||
|
// manager.stateApi.onRegionMaskImageCached(ca.id, imageDTO);
|
||||||
|
return imageDTO;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getInpaintMaskImage(arg: {
|
export async function getInpaintMaskImage(arg: {
|
||||||
manager: CanvasManager;
|
manager: CanvasManager;
|
||||||
bbox?: Rect;
|
bbox?: Rect;
|
||||||
@ -464,7 +509,7 @@ export async function getInpaintMaskImage(arg: {
|
|||||||
return imageDTO;
|
return imageDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getImageSourceImage(arg: {
|
export async function getCompositeLayerImage(arg: {
|
||||||
manager: CanvasManager;
|
manager: CanvasManager;
|
||||||
bbox?: Rect;
|
bbox?: Rect;
|
||||||
preview?: boolean;
|
preview?: boolean;
|
||||||
|
@ -6,6 +6,7 @@ import { bboxReducers } from 'features/controlLayers/store/bboxReducers';
|
|||||||
import { compositingReducers } from 'features/controlLayers/store/compositingReducers';
|
import { compositingReducers } from 'features/controlLayers/store/compositingReducers';
|
||||||
import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers';
|
import { controlAdaptersReducers } from 'features/controlLayers/store/controlAdaptersReducers';
|
||||||
import { documentReducers } from 'features/controlLayers/store/documentReducers';
|
import { documentReducers } from 'features/controlLayers/store/documentReducers';
|
||||||
|
import { initialImageReducers } from 'features/controlLayers/store/initialImageReducers';
|
||||||
import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers';
|
import { inpaintMaskReducers } from 'features/controlLayers/store/inpaintMaskReducers';
|
||||||
import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers';
|
import { ipAdaptersReducers } from 'features/controlLayers/store/ipAdaptersReducers';
|
||||||
import { layersReducers } from 'features/controlLayers/store/layersReducers';
|
import { layersReducers } from 'features/controlLayers/store/layersReducers';
|
||||||
@ -30,6 +31,14 @@ const initialState: CanvasV2State = {
|
|||||||
ipAdapters: { entities: [] },
|
ipAdapters: { entities: [] },
|
||||||
regions: { entities: [] },
|
regions: { entities: [] },
|
||||||
loras: [],
|
loras: [],
|
||||||
|
initialImage: {
|
||||||
|
id: 'initial_image',
|
||||||
|
type: 'initial_image',
|
||||||
|
bbox: null,
|
||||||
|
bboxNeedsUpdate: false,
|
||||||
|
isEnabled: true,
|
||||||
|
imageObject: null,
|
||||||
|
},
|
||||||
inpaintMask: {
|
inpaintMask: {
|
||||||
id: 'inpaint_mask',
|
id: 'inpaint_mask',
|
||||||
type: 'inpaint_mask',
|
type: 'inpaint_mask',
|
||||||
@ -141,6 +150,7 @@ export const canvasV2Slice = createSlice({
|
|||||||
...inpaintMaskReducers,
|
...inpaintMaskReducers,
|
||||||
...sessionReducers,
|
...sessionReducers,
|
||||||
...documentReducers,
|
...documentReducers,
|
||||||
|
...initialImageReducers,
|
||||||
entitySelected: (state, action: PayloadAction<CanvasEntityIdentifier>) => {
|
entitySelected: (state, action: PayloadAction<CanvasEntityIdentifier>) => {
|
||||||
state.selectedEntityIdentifier = action.payload;
|
state.selectedEntityIdentifier = action.payload;
|
||||||
},
|
},
|
||||||
@ -338,6 +348,11 @@ export const {
|
|||||||
sessionStagingCanceled,
|
sessionStagingCanceled,
|
||||||
sessionNextStagedImageSelected,
|
sessionNextStagedImageSelected,
|
||||||
sessionPrevStagedImageSelected,
|
sessionPrevStagedImageSelected,
|
||||||
|
// Initial image
|
||||||
|
iiRecalled,
|
||||||
|
iiIsEnabledToggled,
|
||||||
|
iiReset,
|
||||||
|
iiImageChanged,
|
||||||
} = canvasV2Slice.actions;
|
} = canvasV2Slice.actions;
|
||||||
|
|
||||||
export const selectCanvasV2Slice = (state: RootState) => state.canvasV2;
|
export const selectCanvasV2Slice = (state: RootState) => state.canvasV2;
|
||||||
|
@ -28,6 +28,11 @@ export const documentReducers = {
|
|||||||
if (!state.session.isActive) {
|
if (!state.session.isActive) {
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
state.bbox.rect.width = state.document.rect.width;
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
state.bbox.rect.height = state.document.rect.height;
|
||||||
|
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.document.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.document.rect.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
documentHeightChanged: (
|
documentHeightChanged: (
|
||||||
@ -51,6 +56,11 @@ export const documentReducers = {
|
|||||||
if (!state.session.isActive) {
|
if (!state.session.isActive) {
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
state.bbox.rect.width = state.document.rect.width;
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
state.bbox.rect.height = state.document.rect.height;
|
||||||
|
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.document.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.document.rect.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
documentAspectRatioLockToggled: (state) => {
|
documentAspectRatioLockToggled: (state) => {
|
||||||
@ -74,6 +84,11 @@ export const documentReducers = {
|
|||||||
if (!state.session.isActive) {
|
if (!state.session.isActive) {
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
state.bbox.rect.width = state.document.rect.width;
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
state.bbox.rect.height = state.document.rect.height;
|
||||||
|
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.document.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.document.rect.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
documentDimensionsSwapped: (state) => {
|
documentDimensionsSwapped: (state) => {
|
||||||
@ -95,6 +110,11 @@ export const documentReducers = {
|
|||||||
if (!state.session.isActive) {
|
if (!state.session.isActive) {
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
state.bbox.rect.width = state.document.rect.width;
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
state.bbox.rect.height = state.document.rect.height;
|
||||||
|
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.document.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.document.rect.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
documentSizeOptimized: (state) => {
|
documentSizeOptimized: (state) => {
|
||||||
@ -111,6 +131,11 @@ export const documentReducers = {
|
|||||||
if (!state.session.isActive) {
|
if (!state.session.isActive) {
|
||||||
state.bbox.rect.width = state.document.rect.width;
|
state.bbox.rect.width = state.document.rect.width;
|
||||||
state.bbox.rect.height = state.document.rect.height;
|
state.bbox.rect.height = state.document.rect.height;
|
||||||
|
|
||||||
|
if (state.initialImage.imageObject) {
|
||||||
|
state.initialImage.imageObject.width = state.document.rect.width;
|
||||||
|
state.initialImage.imageObject.height = state.document.rect.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
} satisfies SliceCaseReducers<CanvasV2State>;
|
} satisfies SliceCaseReducers<CanvasV2State>;
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
|
import type { CanvasV2State, InitialImageEntity } from './types';
|
||||||
|
import { imageDTOToImageObject } from './types';
|
||||||
|
|
||||||
|
export const initialImageReducers = {
|
||||||
|
iiRecalled: (state, action: PayloadAction<{ data: InitialImageEntity }>) => {
|
||||||
|
const { data } = action.payload;
|
||||||
|
state.initialImage = data;
|
||||||
|
state.selectedEntityIdentifier = { type: 'initial_image', id: 'initial_image' };
|
||||||
|
},
|
||||||
|
iiIsEnabledToggled: (state) => {
|
||||||
|
if (!state.initialImage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.initialImage.isEnabled = !state.initialImage.isEnabled;
|
||||||
|
},
|
||||||
|
iiReset: (state) => {
|
||||||
|
state.initialImage.imageObject = null;
|
||||||
|
},
|
||||||
|
iiImageChanged: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => {
|
||||||
|
const { imageDTO } = action.payload;
|
||||||
|
if (!state.initialImage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newImageObject = imageDTOToImageObject('initial_image', 'initial_image_object', imageDTO);
|
||||||
|
if (isEqual(newImageObject, state.initialImage.imageObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.initialImage.bbox = null;
|
||||||
|
state.initialImage.bboxNeedsUpdate = true;
|
||||||
|
state.initialImage.isEnabled = true;
|
||||||
|
state.initialImage.imageObject = newImageObject;
|
||||||
|
state.selectedEntityIdentifier = { type: 'initial_image', id: 'initial_image' };
|
||||||
|
},
|
||||||
|
} satisfies SliceCaseReducers<CanvasV2State>;
|
@ -668,6 +668,16 @@ const zInpaintMaskEntity = z.object({
|
|||||||
});
|
});
|
||||||
export type InpaintMaskEntity = z.infer<typeof zInpaintMaskEntity>;
|
export type InpaintMaskEntity = z.infer<typeof zInpaintMaskEntity>;
|
||||||
|
|
||||||
|
const zInitialImageEntity = z.object({
|
||||||
|
id: z.literal('initial_image'),
|
||||||
|
type: z.literal('initial_image'),
|
||||||
|
isEnabled: z.boolean(),
|
||||||
|
bbox: zRect.nullable(),
|
||||||
|
bboxNeedsUpdate: z.boolean(),
|
||||||
|
imageObject: zImageObject.nullable(),
|
||||||
|
});
|
||||||
|
export type InitialImageEntity = z.infer<typeof zInitialImageEntity>;
|
||||||
|
|
||||||
const zControlAdapterEntityBase = z.object({
|
const zControlAdapterEntityBase = z.object({
|
||||||
id: zId,
|
id: zId,
|
||||||
type: z.literal('control_adapter'),
|
type: z.literal('control_adapter'),
|
||||||
@ -790,7 +800,13 @@ export type BoundingBoxScaleMethod = z.infer<typeof zBoundingBoxScaleMethod>;
|
|||||||
export const isBoundingBoxScaleMethod = (v: unknown): v is BoundingBoxScaleMethod =>
|
export const isBoundingBoxScaleMethod = (v: unknown): v is BoundingBoxScaleMethod =>
|
||||||
zBoundingBoxScaleMethod.safeParse(v).success;
|
zBoundingBoxScaleMethod.safeParse(v).success;
|
||||||
|
|
||||||
export type CanvasEntity = LayerEntity | ControlAdapterEntity | RegionEntity | InpaintMaskEntity | IPAdapterEntity;
|
export type CanvasEntity =
|
||||||
|
| LayerEntity
|
||||||
|
| ControlAdapterEntity
|
||||||
|
| RegionEntity
|
||||||
|
| InpaintMaskEntity
|
||||||
|
| IPAdapterEntity
|
||||||
|
| InitialImageEntity;
|
||||||
export type CanvasEntityIdentifier = Pick<CanvasEntity, 'id' | 'type'>;
|
export type CanvasEntityIdentifier = Pick<CanvasEntity, 'id' | 'type'>;
|
||||||
|
|
||||||
export type Size = {
|
export type Size = {
|
||||||
@ -822,6 +838,7 @@ export type CanvasV2State = {
|
|||||||
ipAdapters: { entities: IPAdapterEntity[] };
|
ipAdapters: { entities: IPAdapterEntity[] };
|
||||||
regions: { entities: RegionEntity[] };
|
regions: { entities: RegionEntity[] };
|
||||||
loras: LoRA[];
|
loras: LoRA[];
|
||||||
|
initialImage: InitialImageEntity;
|
||||||
tool: {
|
tool: {
|
||||||
selected: Tool;
|
selected: Tool;
|
||||||
selectedBuffer: Tool | null;
|
selectedBuffer: Tool | null;
|
||||||
|
@ -66,6 +66,10 @@ type UpscaleInitialImageDropData = BaseDropData & {
|
|||||||
actionType: 'SET_UPSCALE_INITIAL_IMAGE';
|
actionType: 'SET_UPSCALE_INITIAL_IMAGE';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type InitialImageDropData = BaseDropData & {
|
||||||
|
actionType: 'SET_INITIAL_IMAGE';
|
||||||
|
};
|
||||||
|
|
||||||
type NodesImageDropData = BaseDropData & {
|
type NodesImageDropData = BaseDropData & {
|
||||||
actionType: 'SET_NODES_IMAGE';
|
actionType: 'SET_NODES_IMAGE';
|
||||||
context: {
|
context: {
|
||||||
@ -101,7 +105,8 @@ export type TypesafeDroppableData =
|
|||||||
| RGIPAdapterImageDropData
|
| RGIPAdapterImageDropData
|
||||||
| SelectForCompareDropData
|
| SelectForCompareDropData
|
||||||
| RasterLayerImageDropData
|
| RasterLayerImageDropData
|
||||||
| UpscaleInitialImageDropData;
|
| UpscaleInitialImageDropData
|
||||||
|
| LayerImageDropData;
|
||||||
|
|
||||||
type BaseDragData = {
|
type BaseDragData = {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -29,6 +29,8 @@ export const isValidDrop = (overData?: TypesafeDroppableData | null, activeData?
|
|||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'SELECT_FOR_COMPARE':
|
case 'SELECT_FOR_COMPARE':
|
||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
|
case 'SET_INITIAL_IMAGE':
|
||||||
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'ADD_TO_BOARD': {
|
case 'ADD_TO_BOARD': {
|
||||||
// If the board is the same, don't allow the drop
|
// If the board is the same, don't allow the drop
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ export const addImageToImage = async (
|
|||||||
): Promise<Invocation<'img_resize' | 'l2i'>> => {
|
): Promise<Invocation<'img_resize' | 'l2i'>> => {
|
||||||
denoise.denoising_start = denoising_start;
|
denoise.denoising_start = denoising_start;
|
||||||
|
|
||||||
const cropBbox = pick(bbox, ['x', 'y', 'width', 'height']);
|
const cropBbox = pick(bbox.rect, ['x', 'y', 'width', 'height']);
|
||||||
const initialImage = await manager.getImageSourceImage({ bbox: cropBbox });
|
const initialImage = await manager.getInitialImage({ bbox: cropBbox });
|
||||||
|
|
||||||
if (!isEqual(scaledSize, originalSize)) {
|
if (!isEqual(scaledSize, originalSize)) {
|
||||||
// Resize the initial image to the scaled size, denoise, then resize back to the original size
|
// Resize the initial image to the scaled size, denoise, then resize back to the original size
|
||||||
|
@ -21,8 +21,8 @@ export const addInpaint = async (
|
|||||||
): Promise<Invocation<'canvas_paste_back'>> => {
|
): Promise<Invocation<'canvas_paste_back'>> => {
|
||||||
denoise.denoising_start = denoising_start;
|
denoise.denoising_start = denoising_start;
|
||||||
|
|
||||||
const cropBbox = pick(bbox, ['x', 'y', 'width', 'height']);
|
const cropBbox = pick(bbox.rect, ['x', 'y', 'width', 'height']);
|
||||||
const initialImage = await manager.getImageSourceImage({ bbox: cropBbox });
|
const initialImage = await manager.getInitialImage({ bbox: cropBbox });
|
||||||
const maskImage = await manager.getInpaintMaskImage({ bbox: cropBbox });
|
const maskImage = await manager.getInpaintMaskImage({ bbox: cropBbox });
|
||||||
|
|
||||||
if (!isEqual(scaledSize, originalSize)) {
|
if (!isEqual(scaledSize, originalSize)) {
|
||||||
|
@ -23,7 +23,7 @@ export const addOutpaint = async (
|
|||||||
denoise.denoising_start = denoising_start;
|
denoise.denoising_start = denoising_start;
|
||||||
|
|
||||||
const cropBbox = pick(bbox, ['x', 'y', 'width', 'height']);
|
const cropBbox = pick(bbox, ['x', 'y', 'width', 'height']);
|
||||||
const initialImage = await manager.getImageSourceImage({ bbox: cropBbox });
|
const initialImage = await manager.getInitialImage({ bbox: cropBbox });
|
||||||
const maskImage = await manager.getInpaintMaskImage({ bbox: cropBbox });
|
const maskImage = await manager.getInpaintMaskImage({ bbox: cropBbox });
|
||||||
const infill = getInfill(g, compositing);
|
const infill = getInfill(g, compositing);
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { logger } from 'app/logging/logger';
|
||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
||||||
@ -33,9 +34,11 @@ import { isNonRefinerMainModelConfig } from 'services/api/types';
|
|||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
|
|
||||||
import { addRegions } from './addRegions';
|
import { addRegions } from './addRegions';
|
||||||
|
const log = logger('system');
|
||||||
|
|
||||||
export const buildSD1Graph = async (state: RootState, manager: CanvasManager): Promise<Graph> => {
|
export const buildSD1Graph = async (state: RootState, manager: CanvasManager): Promise<Graph> => {
|
||||||
const generationMode = manager.getGenerationMode();
|
const generationMode = manager.getGenerationMode();
|
||||||
|
log.debug({ generationMode }, 'Building SD1/SD2 graph');
|
||||||
|
|
||||||
const { bbox, params } = state.canvasV2;
|
const { bbox, params } = state.canvasV2;
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { logger } from 'app/logging/logger';
|
||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
|
||||||
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
|
||||||
@ -32,9 +33,11 @@ import { isNonRefinerMainModelConfig } from 'services/api/types';
|
|||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
|
|
||||||
import { addRegions } from './addRegions';
|
import { addRegions } from './addRegions';
|
||||||
|
const log = logger('system');
|
||||||
|
|
||||||
export const buildSDXLGraph = async (state: RootState, manager: CanvasManager): Promise<Graph> => {
|
export const buildSDXLGraph = async (state: RootState, manager: CanvasManager): Promise<Graph> => {
|
||||||
const generationMode = manager.getGenerationMode();
|
const generationMode = manager.getGenerationMode();
|
||||||
|
log.debug({ generationMode }, 'Building SDXL graph');
|
||||||
|
|
||||||
const { bbox, params } = state.canvasV2;
|
const { bbox, params } = state.canvasV2;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user