feat(ui): add image ctx menu new canvas without resize option

This commit is contained in:
psychedelicious 2024-11-19 11:29:42 -06:00
parent 5aca04b51b
commit 53d482bade
3 changed files with 61 additions and 10 deletions

View File

@ -1710,7 +1710,9 @@
"inpaintMask": "Inpaint Mask",
"regionalGuidance": "Regional Guidance",
"canvasAsRasterLayer": "$t(controlLayers.canvas) as $t(controlLayers.rasterLayer)",
"canvasAsRasterLayerResize": "$t(controlLayers.canvas) as $t(controlLayers.rasterLayer) (Resize)",
"canvasAsControlLayer": "$t(controlLayers.canvas) as $t(controlLayers.controlLayer)",
"canvasAsControlLayerResize": "$t(controlLayers.canvas) as $t(controlLayers.controlLayer) (Resize)",
"referenceImage": "Reference Image",
"regionalReferenceImage": "Regional Reference Image",
"globalReferenceImage": "Global Reference Image",

View File

@ -27,7 +27,7 @@ export const ImageMenuItemNewFromImageSubMenu = memo(() => {
const onClickNewCanvasWithRasterLayerFromImage = useCallback(() => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, type: 'raster_layer', dispatch, getState });
newCanvasFromImage({ imageDTO, withResize: false, type: 'raster_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
@ -39,7 +39,31 @@ export const ImageMenuItemNewFromImageSubMenu = memo(() => {
const onClickNewCanvasWithControlLayerFromImage = useCallback(() => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, type: 'control_layer', dispatch, getState });
newCanvasFromImage({ imageDTO, withResize: false, type: 'control_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
id: 'SENT_TO_CANVAS',
title: t('toast.sentToCanvas'),
status: 'success',
});
}, [imageDTO, imageViewer, store, t]);
const onClickNewCanvasWithRasterLayerFromImageWithResize = useCallback(() => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, withResize: true, type: 'raster_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
id: 'SENT_TO_CANVAS',
title: t('toast.sentToCanvas'),
status: 'success',
});
}, [imageDTO, imageViewer, store, t]);
const onClickNewCanvasWithControlLayerFromImageWithResize = useCallback(() => {
const { dispatch, getState } = store;
newCanvasFromImage({ imageDTO, withResize: true, type: 'control_layer', dispatch, getState });
dispatch(setActiveTab('canvas'));
imageViewer.close();
toast({
@ -111,6 +135,13 @@ export const ImageMenuItemNewFromImageSubMenu = memo(() => {
<MenuItem icon={<PiFileBold />} onClickCapture={onClickNewCanvasWithRasterLayerFromImage} isDisabled={isBusy}>
{t('controlLayers.canvasAsRasterLayer')}
</MenuItem>
<MenuItem
icon={<PiFileBold />}
onClickCapture={onClickNewCanvasWithRasterLayerFromImageWithResize}
isDisabled={isBusy}
>
{t('controlLayers.canvasAsRasterLayerResize')}
</MenuItem>
<MenuItem
icon={<PiFileBold />}
onClickCapture={onClickNewCanvasWithControlLayerFromImage}
@ -118,6 +149,13 @@ export const ImageMenuItemNewFromImageSubMenu = memo(() => {
>
{t('controlLayers.canvasAsControlLayer')}
</MenuItem>
<MenuItem
icon={<PiFileBold />}
onClickCapture={onClickNewCanvasWithControlLayerFromImageWithResize}
isDisabled={isBusy || isSD3}
>
{t('controlLayers.canvasAsControlLayerResize')}
</MenuItem>
<MenuItem icon={<NewLayerIcon />} onClickCapture={onClickNewInpaintMaskFromImage} isDisabled={isBusy}>
{t('controlLayers.inpaintMask')}
</MenuItem>

View File

@ -182,21 +182,24 @@ export const createNewCanvasEntityFromImage = (arg: {
};
/**
* Creates a new canvas with the given image as the initial image, replicating the img2img flow:
* Creates a new canvas with the given image as the only layer:
* - Reset the canvas
* - Resize the bbox to the image's aspect ratio at the optimal size for the selected model
* - Add the image as a raster layer
* - Resizes the layer to fit the bbox using the 'fill' strategy
* - Add the image as a layer of the given type
* - If `withResize`: Resizes the layer to fit the bbox using the 'fill' strategy
*
* This allows the user to immediately generate a new image from the given image without any additional steps.
*
* Using 'raster_layer' for the type and enabling `withResize` replicates the common img2img flow.
*/
export const newCanvasFromImage = (arg: {
imageDTO: ImageDTO;
type: CanvasEntityType | 'regional_guidance_with_reference_image';
withResize: boolean;
dispatch: AppDispatch;
getState: () => RootState;
}) => {
const { type, imageDTO, dispatch, getState } = arg;
const { type, imageDTO, withResize, dispatch, getState } = arg;
const state = getState();
const base = selectBboxModelBase(state);
@ -229,7 +232,9 @@ export const newCanvasFromImage = (arg: {
objects: [imageObject],
position: { x, y },
} satisfies Partial<CanvasRasterLayerState>;
addInitCallback(overrides.id);
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));
@ -243,7 +248,9 @@ export const newCanvasFromImage = (arg: {
position: { x, y },
controlAdapter: deepClone(initialControlNet),
} satisfies Partial<CanvasControlLayerState>;
addInitCallback(overrides.id);
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));
@ -256,7 +263,9 @@ export const newCanvasFromImage = (arg: {
objects: [imageObject],
position: { x, y },
} satisfies Partial<CanvasInpaintMaskState>;
addInitCallback(overrides.id);
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));
@ -269,7 +278,9 @@ export const newCanvasFromImage = (arg: {
objects: [imageObject],
position: { x, y },
} satisfies Partial<CanvasRegionalGuidanceState>;
addInitCallback(overrides.id);
if (withResize) {
addInitCallback(overrides.id);
}
dispatch(canvasReset());
// The `bboxChangedFromCanvas` reducer does no validation! Careful!
dispatch(bboxChangedFromCanvas({ x: 0, y: 0, width, height }));