mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Implements invert mask
This commit is contained in:
parent
7f0fb47cf3
commit
7075a17091
@ -12,7 +12,7 @@ import os
|
|||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
from flask import Flask, redirect, send_from_directory, flash, request, url_for, jsonify
|
from flask import Flask, redirect, send_from_directory, flash, request, url_for, jsonify
|
||||||
from flask_socketio import SocketIO
|
from flask_socketio import SocketIO
|
||||||
from PIL import Image
|
from PIL import Image, ImageOps
|
||||||
from PIL.Image import Image as ImageType
|
from PIL.Image import Image as ImageType
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from threading import Event
|
from threading import Event
|
||||||
@ -698,11 +698,11 @@ class InvokeAIWebServer:
|
|||||||
|
|
||||||
So we need to convert each into a PIL Image.
|
So we need to convert each into a PIL Image.
|
||||||
"""
|
"""
|
||||||
|
truncated_outpaint_image_b64 = generation_parameters["init_img"][:64]
|
||||||
truncated_outpaint_mask_b64 = generation_parameters["init_mask"][:64]
|
truncated_outpaint_mask_b64 = generation_parameters["init_mask"][:64]
|
||||||
|
|
||||||
init_img_url = generation_parameters["init_img"]
|
init_img_url = generation_parameters["init_img"]
|
||||||
|
init_mask_url = generation_parameters["init_mask"]
|
||||||
init_img_url = generation_parameters["init_img"]
|
|
||||||
|
|
||||||
init_img_path = self.get_image_path_from_url(init_img_url)
|
init_img_path = self.get_image_path_from_url(init_img_url)
|
||||||
|
|
||||||
@ -723,6 +723,9 @@ class InvokeAIWebServer:
|
|||||||
generation_parameters["init_mask"]
|
generation_parameters["init_mask"]
|
||||||
).convert("L")
|
).convert("L")
|
||||||
|
|
||||||
|
if generation_parameters.invert_mask:
|
||||||
|
mask_image = ImageOps.invert(mask_image)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Apply the mask to the init image, creating a "mask" image with
|
Apply the mask to the init image, creating a "mask" image with
|
||||||
transparency where inpainting should occur. This is the kind of
|
transparency where inpainting should occur. This is the kind of
|
||||||
|
@ -118,6 +118,7 @@ export const frontendToBackendParameters = (
|
|||||||
shouldUseInpaintReplace,
|
shouldUseInpaintReplace,
|
||||||
stageScale,
|
stageScale,
|
||||||
isMaskEnabled,
|
isMaskEnabled,
|
||||||
|
shouldInvertMask,
|
||||||
} = canvasState[canvasState.currentCanvas];
|
} = canvasState[canvasState.currentCanvas];
|
||||||
|
|
||||||
const boundingBox = {
|
const boundingBox = {
|
||||||
@ -137,6 +138,10 @@ export const frontendToBackendParameters = (
|
|||||||
generationParameters.init_img = imageToProcessUrl;
|
generationParameters.init_img = imageToProcessUrl;
|
||||||
generationParameters.strength = img2imgStrength;
|
generationParameters.strength = img2imgStrength;
|
||||||
|
|
||||||
|
if (shouldInvertMask) {
|
||||||
|
generationParameters.invert_mask = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldUseInpaintReplace) {
|
if (shouldUseInpaintReplace) {
|
||||||
generationParameters.inpaint_replace = inpaintReplace;
|
generationParameters.inpaint_replace = inpaintReplace;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
setIsMaskEnabled,
|
setIsMaskEnabled,
|
||||||
setLayer,
|
setLayer,
|
||||||
setMaskColor,
|
setMaskColor,
|
||||||
|
setShouldInvertMask,
|
||||||
} from './canvasSlice';
|
} from './canvasSlice';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store';
|
import { useAppDispatch, useAppSelector } from 'app/store';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@ -19,12 +20,13 @@ import IAIButton from 'common/components/IAIButton';
|
|||||||
export const selector = createSelector(
|
export const selector = createSelector(
|
||||||
[currentCanvasSelector],
|
[currentCanvasSelector],
|
||||||
(currentCanvas) => {
|
(currentCanvas) => {
|
||||||
const { maskColor, layer, isMaskEnabled } = currentCanvas;
|
const { maskColor, layer, isMaskEnabled, shouldInvertMask } = currentCanvas;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
layer,
|
layer,
|
||||||
maskColor,
|
maskColor,
|
||||||
isMaskEnabled,
|
isMaskEnabled,
|
||||||
|
shouldInvertMask,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -35,7 +37,8 @@ export const selector = createSelector(
|
|||||||
);
|
);
|
||||||
const IAICanvasMaskButtonPopover = () => {
|
const IAICanvasMaskButtonPopover = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { layer, maskColor, isMaskEnabled } = useAppSelector(selector);
|
const { layer, maskColor, isMaskEnabled, shouldInvertMask } =
|
||||||
|
useAppSelector(selector);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IAIPopover
|
<IAIPopover
|
||||||
@ -57,7 +60,11 @@ const IAICanvasMaskButtonPopover = () => {
|
|||||||
isChecked={isMaskEnabled}
|
isChecked={isMaskEnabled}
|
||||||
onChange={(e) => dispatch(setIsMaskEnabled(e.target.checked))}
|
onChange={(e) => dispatch(setIsMaskEnabled(e.target.checked))}
|
||||||
/>
|
/>
|
||||||
<IAICheckbox label="Invert Mask" />
|
<IAICheckbox
|
||||||
|
label="Invert Mask"
|
||||||
|
isChecked={shouldInvertMask}
|
||||||
|
onChange={(e) => dispatch(setShouldInvertMask(e.target.checked))}
|
||||||
|
/>
|
||||||
<IAIColorPicker
|
<IAIColorPicker
|
||||||
color={maskColor}
|
color={maskColor}
|
||||||
onChange={(newColor) => dispatch(setMaskColor(newColor))}
|
onChange={(newColor) => dispatch(setMaskColor(newColor))}
|
||||||
|
@ -15,14 +15,20 @@ import Konva from 'konva';
|
|||||||
export const canvasMaskCompositerSelector = createSelector(
|
export const canvasMaskCompositerSelector = createSelector(
|
||||||
currentCanvasSelector,
|
currentCanvasSelector,
|
||||||
(currentCanvas) => {
|
(currentCanvas) => {
|
||||||
const { maskColor, stageCoordinates, stageDimensions, stageScale } =
|
const {
|
||||||
currentCanvas as InpaintingCanvasState | OutpaintingCanvasState;
|
maskColor,
|
||||||
|
stageCoordinates,
|
||||||
|
stageDimensions,
|
||||||
|
stageScale,
|
||||||
|
shouldInvertMask,
|
||||||
|
} = currentCanvas as InpaintingCanvasState | OutpaintingCanvasState;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stageCoordinates,
|
stageCoordinates,
|
||||||
stageDimensions,
|
stageDimensions,
|
||||||
stageScale,
|
stageScale,
|
||||||
maskColorString: rgbaColorToString(maskColor),
|
maskColorString: rgbaColorToString(maskColor),
|
||||||
|
shouldInvertMask,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -114,8 +120,13 @@ const getColoredSVG = (color: string) => {
|
|||||||
const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
||||||
const { ...rest } = props;
|
const { ...rest } = props;
|
||||||
|
|
||||||
const { maskColorString, stageCoordinates, stageDimensions, stageScale } =
|
const {
|
||||||
useAppSelector(canvasMaskCompositerSelector);
|
maskColorString,
|
||||||
|
stageCoordinates,
|
||||||
|
stageDimensions,
|
||||||
|
stageScale,
|
||||||
|
shouldInvertMask,
|
||||||
|
} = useAppSelector(canvasMaskCompositerSelector);
|
||||||
|
|
||||||
const [fillPatternImage, setFillPatternImage] =
|
const [fillPatternImage, setFillPatternImage] =
|
||||||
useState<HTMLImageElement | null>(null);
|
useState<HTMLImageElement | null>(null);
|
||||||
@ -162,7 +173,7 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
|||||||
fillPatternRepeat={'repeat'}
|
fillPatternRepeat={'repeat'}
|
||||||
fillPatternScale={{ x: 1 / stageScale, y: 1 / stageScale }}
|
fillPatternScale={{ x: 1 / stageScale, y: 1 / stageScale }}
|
||||||
listening={true}
|
listening={true}
|
||||||
globalCompositeOperation={'source-in'}
|
globalCompositeOperation={shouldInvertMask ? 'source-out' : 'source-in'}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -546,25 +546,38 @@ export const canvasSlice = createSlice({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
addLine: (state, action: PayloadAction<number[]>) => {
|
addLine: (state, action: PayloadAction<number[]>) => {
|
||||||
const { tool, layer, brushColor, brushSize, eraserSize } =
|
const currentCanvas = state[state.currentCanvas];
|
||||||
state[state.currentCanvas];
|
|
||||||
|
const { tool, layer, brushColor, brushSize, eraserSize } = currentCanvas;
|
||||||
|
|
||||||
if (tool === 'move') return;
|
if (tool === 'move') return;
|
||||||
|
|
||||||
state[state.currentCanvas].pastObjects.push(
|
let newTool: CanvasDrawingTool;
|
||||||
state[state.currentCanvas].objects
|
|
||||||
);
|
|
||||||
|
|
||||||
state[state.currentCanvas].objects.push({
|
if (layer === 'mask' && currentCanvas.shouldInvertMask) {
|
||||||
|
newTool = tool === 'eraser' ? 'brush' : 'eraser';
|
||||||
|
} else {
|
||||||
|
newTool = tool;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newStrokeWidth = tool === 'brush' ? brushSize / 2 : eraserSize / 2;
|
||||||
|
|
||||||
|
// set & then spread this to only conditionally add the "color" key
|
||||||
|
const newColor =
|
||||||
|
layer === 'base' && tool === 'brush' ? { color: brushColor } : {};
|
||||||
|
|
||||||
|
currentCanvas.pastObjects.push(currentCanvas.objects);
|
||||||
|
|
||||||
|
currentCanvas.objects.push({
|
||||||
kind: 'line',
|
kind: 'line',
|
||||||
layer,
|
layer,
|
||||||
tool,
|
tool: newTool,
|
||||||
strokeWidth: tool === 'brush' ? brushSize / 2 : eraserSize / 2,
|
strokeWidth: newStrokeWidth,
|
||||||
points: action.payload,
|
points: action.payload,
|
||||||
...(layer === 'base' && tool === 'brush' && { color: brushColor }),
|
...newColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
state[state.currentCanvas].futureObjects = [];
|
currentCanvas.futureObjects = [];
|
||||||
},
|
},
|
||||||
addPointToCurrentLine: (state, action: PayloadAction<number[]>) => {
|
addPointToCurrentLine: (state, action: PayloadAction<number[]>) => {
|
||||||
const lastLine =
|
const lastLine =
|
||||||
@ -579,14 +592,18 @@ export const canvasSlice = createSlice({
|
|||||||
|
|
||||||
const newObjects = state[state.currentCanvas].pastObjects.pop();
|
const newObjects = state[state.currentCanvas].pastObjects.pop();
|
||||||
if (!newObjects) return;
|
if (!newObjects) return;
|
||||||
state[state.currentCanvas].futureObjects.unshift(state[state.currentCanvas].objects);
|
state[state.currentCanvas].futureObjects.unshift(
|
||||||
|
state[state.currentCanvas].objects
|
||||||
|
);
|
||||||
state[state.currentCanvas].objects = newObjects;
|
state[state.currentCanvas].objects = newObjects;
|
||||||
},
|
},
|
||||||
redo: (state) => {
|
redo: (state) => {
|
||||||
if (state[state.currentCanvas].futureObjects.length === 0) return;
|
if (state[state.currentCanvas].futureObjects.length === 0) return;
|
||||||
const newObjects = state[state.currentCanvas].futureObjects.shift();
|
const newObjects = state[state.currentCanvas].futureObjects.shift();
|
||||||
if (!newObjects) return;
|
if (!newObjects) return;
|
||||||
state[state.currentCanvas].pastObjects.push(state[state.currentCanvas].objects);
|
state[state.currentCanvas].pastObjects.push(
|
||||||
|
state[state.currentCanvas].objects
|
||||||
|
);
|
||||||
state[state.currentCanvas].objects = newObjects;
|
state[state.currentCanvas].objects = newObjects;
|
||||||
},
|
},
|
||||||
setShouldShowGrid: (state, action: PayloadAction<boolean>) => {
|
setShouldShowGrid: (state, action: PayloadAction<boolean>) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user