feat(ui): use resize on uplaod functionality when creating new canvas from image

This commit is contained in:
psychedelicious
2025-05-28 20:14:22 +10:00
parent 845a321a43
commit 31a96d2945
2 changed files with 27 additions and 39 deletions

View File

@@ -19,9 +19,9 @@ export const ImageMenuItemNewCanvasFromImageSubMenu = memo(() => {
const imageViewer = useImageViewer();
const isBusy = useCanvasIsBusySafe();
const onClickNewCanvasWithRasterLayerFromImage = useCallback(() => {
const onClickNewCanvasWithRasterLayerFromImage = useCallback(async () => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, withResize: false, type: 'raster_layer', dispatch, getState });
await newCanvasFromImage({ imageDTO, withResize: false, type: 'raster_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
@@ -31,9 +31,9 @@ export const ImageMenuItemNewCanvasFromImageSubMenu = memo(() => {
});
}, [imageDTO, imageViewer, store, t]);
const onClickNewCanvasWithControlLayerFromImage = useCallback(() => {
const onClickNewCanvasWithControlLayerFromImage = useCallback(async () => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, withResize: false, type: 'control_layer', dispatch, getState });
await newCanvasFromImage({ imageDTO, withResize: false, type: 'control_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
@@ -43,9 +43,9 @@ export const ImageMenuItemNewCanvasFromImageSubMenu = memo(() => {
});
}, [imageDTO, imageViewer, store, t]);
const onClickNewCanvasWithRasterLayerFromImageWithResize = useCallback(() => {
const onClickNewCanvasWithRasterLayerFromImageWithResize = useCallback(async () => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, withResize: true, type: 'raster_layer', dispatch, getState });
await newCanvasFromImage({ imageDTO, withResize: true, type: 'raster_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
@@ -55,9 +55,9 @@ export const ImageMenuItemNewCanvasFromImageSubMenu = memo(() => {
});
}, [imageDTO, imageViewer, store, t]);
const onClickNewCanvasWithControlLayerFromImageWithResize = useCallback(() => {
const onClickNewCanvasWithControlLayerFromImageWithResize = useCallback(async () => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, withResize: true, type: 'control_layer', dispatch, getState });
await newCanvasFromImage({ imageDTO, withResize: true, type: 'control_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({

View File

@@ -1,7 +1,6 @@
import type { AppDispatch, RootState } from 'app/store/store';
import { deepClone } from 'common/util/deepClone';
import { selectDefaultIPAdapter, selectDefaultRefImageConfig } from 'features/controlLayers/hooks/addLayerHooks';
import { CanvasEntityAdapterBase } from 'features/controlLayers/konva/CanvasEntity/CanvasEntityAdapterBase';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { canvasReset } from 'features/controlLayers/store/actions';
import {
@@ -20,6 +19,7 @@ import type {
CanvasControlLayerState,
CanvasEntityIdentifier,
CanvasEntityType,
CanvasImageState,
CanvasInpaintMaskState,
CanvasRasterLayerState,
CanvasRegionalGuidanceState,
@@ -34,7 +34,7 @@ import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
import type { FieldIdentifier } from 'features/nodes/types/field';
import { upscaleInitialImageChanged } from 'features/parameters/store/upscaleSlice';
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
import { imagesApi } from 'services/api/endpoints/images';
import { imageDTOToFile, imagesApi, uploadImage } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types';
import type { Equals } from 'tsafe';
import { assert } from 'tsafe';
@@ -142,14 +142,14 @@ export const createNewCanvasEntityFromImage = (arg: {
*
* Using 'raster_layer' for the type and enabling `withResize` replicates the common img2img flow.
*/
export const newCanvasFromImage = (arg: {
export const newCanvasFromImage = async (arg: {
imageDTO: ImageDTO;
type: CanvasEntityType | 'regional_guidance_with_reference_image';
withResize: boolean;
withResize?: boolean;
dispatch: AppDispatch;
getState: () => RootState;
}) => {
const { type, imageDTO, withResize, dispatch, getState } = arg;
const { type, imageDTO, withResize = false, dispatch, getState } = arg;
const state = getState();
const base = selectBboxModelBase(state);
@@ -158,22 +158,22 @@ export const newCanvasFromImage = (arg: {
const optimalDimension = getOptimalDimension(base);
const { width, height } = calculateNewSize(ratio, optimalDimension ** 2, base);
const imageObject = imageDTOToImageObject(imageDTO);
const { x, y } = selectBboxRect(state);
let imageObject: CanvasImageState;
const addInitCallback = (id: string) => {
CanvasEntityAdapterBase.registerInitCallback(async (adapter) => {
// Skip the callback if the adapter is not the one we are creating
if (adapter.id !== id) {
return false;
}
// Fit the layer to the bbox w/ fill strategy
await adapter.transformer.startTransform({ silent: true });
adapter.transformer.fitToBboxFill();
await adapter.transformer.applyTransform();
return true;
if (withResize && (width !== imageDTO.width || height !== imageDTO.height)) {
const resizedImageDTO = await uploadImage({
file: await imageDTOToFile(imageDTO),
image_category: 'general',
is_intermediate: true,
silent: true,
resize_to: { width, height },
});
};
imageObject = imageDTOToImageObject(resizedImageDTO);
} else {
imageObject = imageDTOToImageObject(imageDTO);
}
const { x, y } = selectBboxRect(state);
switch (type) {
case 'raster_layer': {
@@ -182,9 +182,6 @@ export const newCanvasFromImage = (arg: {
objects: [imageObject],
position: { x, y },
} satisfies Partial<CanvasRasterLayerState>;
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));
@@ -198,9 +195,6 @@ export const newCanvasFromImage = (arg: {
position: { x, y },
controlAdapter: deepClone(initialControlNet),
} satisfies Partial<CanvasControlLayerState>;
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));
@@ -213,9 +207,6 @@ export const newCanvasFromImage = (arg: {
objects: [imageObject],
position: { x, y },
} satisfies Partial<CanvasInpaintMaskState>;
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));
@@ -228,9 +219,6 @@ export const newCanvasFromImage = (arg: {
objects: [imageObject],
position: { x, y },
} satisfies Partial<CanvasRegionalGuidanceState>;
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));