feat(ui): add compositeMaskedRegions setting

This commit is contained in:
psychedelicious
2024-09-03 18:42:27 +10:00
parent 1349e73a1a
commit f83b500645
6 changed files with 56 additions and 8 deletions

View File

@@ -1673,6 +1673,7 @@
"clearCaches": "Clear Caches",
"recalculateRects": "Recalculate Rects",
"clipToBbox": "Clip Strokes to Bbox",
"compositeMaskedRegions": "Composite Masked Regions",
"addLayer": "Add Layer",
"duplicate": "Duplicate",
"moveToFront": "Move to Front",

View File

@@ -0,0 +1,33 @@
import { Checkbox, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import {
selectCanvasSettingsSlice,
settingsCompositeMaskedRegionsChanged,
} from 'features/controlLayers/store/canvasSettingsSlice';
import type { ChangeEvent } from 'react';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
const selectCompositeMaskedRegions = createSelector(
selectCanvasSettingsSlice,
(canvasSettings) => canvasSettings.compositeMaskedRegions
);
export const CanvasSettingsCompositeMaskedRegionsCheckbox = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const compositeMaskedRegions = useAppSelector(selectCompositeMaskedRegions);
const onChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => dispatch(settingsCompositeMaskedRegionsChanged(e.target.checked)),
[dispatch]
);
return (
<FormControl w="full">
<FormLabel flexGrow={1}>{t('controlLayers.compositeMaskedRegions')}</FormLabel>
<Checkbox isChecked={compositeMaskedRegions} onChange={onChange} />
</FormControl>
);
});
CanvasSettingsCompositeMaskedRegionsCheckbox.displayName = 'CanvasSettingsCompositeMaskedRegionsCheckbox';

View File

@@ -13,6 +13,7 @@ import { CanvasSettingsAutoSaveCheckbox } from 'features/controlLayers/component
import { CanvasSettingsClearCachesButton } from 'features/controlLayers/components/Settings/CanvasSettingsClearCachesButton';
import { CanvasSettingsClearHistoryButton } from 'features/controlLayers/components/Settings/CanvasSettingsClearHistoryButton';
import { CanvasSettingsClipToBboxCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsClipToBboxCheckbox';
import { CanvasSettingsCompositeMaskedRegionsCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsCompositeMaskedRegionsCheckbox';
import { CanvasSettingsDynamicGridSwitch } from 'features/controlLayers/components/Settings/CanvasSettingsDynamicGridSwitch';
import { CanvasSettingsInvertScrollCheckbox } from 'features/controlLayers/components/Settings/CanvasSettingsInvertScrollCheckbox';
import { CanvasSettingsLogDebugInfoButton } from 'features/controlLayers/components/Settings/CanvasSettingsLogDebugInfo';
@@ -37,6 +38,7 @@ export const CanvasSettingsPopover = memo(() => {
<CanvasSettingsAutoSaveCheckbox />
<CanvasSettingsInvertScrollCheckbox />
<CanvasSettingsClipToBboxCheckbox />
<CanvasSettingsCompositeMaskedRegionsCheckbox />
<CanvasSettingsDynamicGridSwitch />
<CanvasSettingsShowHUDSwitch />
<CanvasSettingsResetButton />

View File

@@ -8,8 +8,9 @@ export type CanvasSettingsState = {
*/
showHUD: boolean;
/**
* Whether to automatically save canvas generations to the gallery. If in Save to Gallery mode, this setting will be
* ignored, and all generations will be saved.
* Whether to automatically save canvas generations to the gallery.
*
* When `sendToCanvas` is disabled, this setting is ignored, and images are always saved to the gallery.
*/
autoSave: boolean;
/**
@@ -42,6 +43,14 @@ export type CanvasSettingsState = {
* the gallery.
*/
sendToCanvas: boolean;
/**
* Whether to composite inpainted/outpainted regions back onto the source image when saving canvas generations.
*
* If disabled, inpainted/outpainted regions will be saved with a transparent background.
*
* When `sendToCanvas` is disabled, this setting is ignored, masked regions will always be composited.
*/
compositeMaskedRegions: boolean;
// TODO(psyche): These are copied from old canvas state, need to be implemented
// imageSmoothing: boolean;
@@ -59,6 +68,7 @@ const initialState: CanvasSettingsState = {
invertScrollForToolWidth: false,
color: { r: 31, g: 160, b: 224, a: 1 }, // invokeBlue.500
sendToCanvas: false,
compositeMaskedRegions: false,
};
export const canvasSettingsSlice = createSlice({
@@ -92,6 +102,9 @@ export const canvasSettingsSlice = createSlice({
settingsSendToCanvasChanged: (state, action: PayloadAction<boolean>) => {
state.sendToCanvas = action.payload;
},
settingsCompositeMaskedRegionsChanged: (state, action: PayloadAction<boolean>) => {
state.compositeMaskedRegions = action.payload;
},
},
});
@@ -105,6 +118,7 @@ export const {
settingsColorChanged,
settingsInvertScrollForToolWidthChanged,
settingsSendToCanvasChanged,
settingsCompositeMaskedRegionsChanged,
} = canvasSettingsSlice.actions;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */

View File

@@ -29,7 +29,6 @@ export const addInpaint = async (
const canvas = selectCanvasSlice(state);
const { bbox } = canvas;
const { sendToCanvas } = canvasSettings;
const initialImage = await manager.compositor.getCompositeRasterLayerImageDTO(bbox.rect);
const maskImage = await manager.compositor.getCompositeInpaintMaskImageDTO(bbox.rect);
@@ -99,7 +98,7 @@ export const addInpaint = async (
g.addEdge(resizeImageToOriginalSize, 'image', canvasPasteBack, 'generated_image');
g.addEdge(resizeMaskToOriginalSize, 'image', canvasPasteBack, 'mask');
if (!sendToCanvas) {
if (!canvasSettings.sendToCanvas || canvasSettings.compositeMaskedRegions) {
canvasPasteBack.source_image = { image_name: initialImage.image_name };
}
@@ -143,7 +142,7 @@ export const addInpaint = async (
g.addEdge(l2i, 'image', canvasPasteBack, 'generated_image');
if (!sendToCanvas) {
if (!canvasSettings.sendToCanvas || canvasSettings.compositeMaskedRegions) {
canvasPasteBack.source_image = { image_name: initialImage.image_name };
}

View File

@@ -30,7 +30,6 @@ export const addOutpaint = async (
const canvas = selectCanvasSlice(state);
const { bbox } = canvas;
const { sendToCanvas } = canvasSettings;
const initialImage = await manager.compositor.getCompositeRasterLayerImageDTO(bbox.rect);
const maskImage = await manager.compositor.getCompositeInpaintMaskImageDTO(bbox.rect);
@@ -123,7 +122,7 @@ export const addOutpaint = async (
g.addEdge(resizeOutputImageToOriginalSize, 'image', canvasPasteBack, 'generated_image');
g.addEdge(resizeOutputMaskToOriginalSize, 'image', canvasPasteBack, 'mask');
if (!sendToCanvas) {
if (!canvasSettings.sendToCanvas || canvasSettings.compositeMaskedRegions) {
canvasPasteBack.source_image = { image_name: initialImage.image_name };
}
@@ -173,7 +172,7 @@ export const addOutpaint = async (
g.addEdge(createGradientMask, 'expanded_mask_area', canvasPasteBack, 'mask');
g.addEdge(l2i, 'image', canvasPasteBack, 'generated_image');
if (!sendToCanvas) {
if (!canvasSettings.sendToCanvas || canvasSettings.compositeMaskedRegions) {
canvasPasteBack.source_image = { image_name: initialImage.image_name };
}