Mask now colorful depending on inversion

Blue masking means SD will try to keep image as-is under the mask. Red
masking means SD will try to replace whatever is under the mask. (Red is
default masking, Blue is inverted masking)

Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
Victor Seiji Hariki 2022-11-26 22:35:16 -03:00
parent fe4b50cb8d
commit fe2ebec569
5 changed files with 79 additions and 11 deletions

View file

@ -146,8 +146,25 @@ body {
position: absolute;
}
/* Mask colors for mask inversion */
/* Filters are some magic acquired at https://codepen.io/sosuke/pen/Pjoqqp */
.maskPaintCanvas {
filter: opacity(40%);
opacity: 0%;
}
.maskPaintCanvas.display {
opacity: 40%;
filter: invert(100%);
}
.maskPaintCanvas.display.clear {
filter: invert(71%) sepia(46%) saturate(6615%) hue-rotate(321deg)
brightness(106%) contrast(100%);
}
.maskPaintCanvas.display.hold {
filter: invert(41%) sepia(16%) saturate(5181%) hue-rotate(218deg)
brightness(103%) contrast(108%);
}
.strokeText {

View file

@ -253,12 +253,18 @@ const dreamTool = () =>
mouse.listen.canvas.onmousemove.on(state.mousemovecb);
mouse.listen.canvas.left.onclick.on(state.dreamcb);
mouse.listen.canvas.right.onclick.on(state.erasecb);
// Display Mask
setMask(state.invertMask ? "hold" : "clear");
},
(state, opt) => {
// Clear Listeners
mouse.listen.canvas.onmousemove.clear(state.mousemovecb);
mouse.listen.canvas.left.onclick.clear(state.dreamcb);
mouse.listen.canvas.right.onclick.clear(state.erasecb);
// Hide Mask
setMask("none");
},
{
init: (state) => {
@ -286,7 +292,10 @@ const dreamTool = () =>
state.ctxmenu.invertMaskLabel = _toolbar_input.checkbox(
state,
"invertMask",
"Invert Mask"
"Invert Mask",
() => {
setMask(state.invertMask ? "hold" : "clear");
}
).label;
// Overmasking Slider
@ -326,12 +335,18 @@ const img2imgTool = () =>
mouse.listen.canvas.onmousemove.on(state.mousemovecb);
mouse.listen.canvas.left.onclick.on(state.dreamcb);
mouse.listen.canvas.right.onclick.on(state.erasecb);
// Display Mask
setMask(state.invertMask ? "hold" : "clear");
},
(state, opt) => {
// Clear Listeners
mouse.listen.canvas.onmousemove.clear(state.mousemovecb);
mouse.listen.canvas.left.onclick.clear(state.dreamcb);
mouse.listen.canvas.right.onclick.clear(state.erasecb);
// Hide mask
setMask("none");
},
{
init: (state) => {
@ -361,7 +376,7 @@ const img2imgTool = () =>
const auxCtx = auxCanvas.getContext("2d");
if (state.keepBorderSize > 0) {
auxCtx.fillStyle = "#6A6AFF50";
auxCtx.fillStyle = "#6A6AFF7F";
auxCtx.fillRect(0, 0, state.keepBorderSize, bb.h);
auxCtx.fillRect(0, 0, bb.w, state.keepBorderSize);
auxCtx.fillRect(
@ -403,7 +418,10 @@ const img2imgTool = () =>
state.ctxmenu.invertMaskLabel = _toolbar_input.checkbox(
state,
"invertMask",
"Invert Mask"
"Invert Mask",
() => {
setMask(state.invertMask ? "hold" : "clear");
}
).label;
// Inpaint Full Resolution Checkbox

View file

@ -1,10 +1,34 @@
const setMask = (state) => {
const canvas = document.querySelector("#maskPaintCanvas");
switch (state) {
case "clear":
canvas.classList.remove("hold");
canvas.classList.add("display", "clear");
break;
case "hold":
canvas.classList.remove("clear");
canvas.classList.add("display", "hold");
break;
case "neutral":
canvas.classList.remove("clear", "hold");
canvas.classList.add("display");
break;
case "none":
canvas.classList.remove("display", "hold", "clear");
break;
default:
console.debug(`Invalid mask type: ${state}`);
break;
}
};
const _mask_brush_draw_callback = (evn, state) => {
if (
(evn.initialTarget && evn.initialTarget.id === "overlayCanvas") ||
(!evn.initialTarget && evn.target.id === "overlayCanvas")
) {
maskPaintCtx.globalCompositeOperation = "source-over";
maskPaintCtx.strokeStyle = "#FF6A6A";
maskPaintCtx.strokeStyle = "black";
maskPaintCtx.lineWidth = state.brushSize;
maskPaintCtx.beginPath();
@ -24,7 +48,7 @@ const _mask_brush_erase_callback = (evn, state) => {
(!evn.initialTarget && evn.target.id === "overlayCanvas")
) {
maskPaintCtx.globalCompositeOperation = "destination-out";
maskPaintCtx.strokeStyle = "#FFFFFFFF";
maskPaintCtx.strokeStyle = "black";
maskPaintCtx.lineWidth = state.brushSize;
maskPaintCtx.beginPath();
@ -54,6 +78,9 @@ const maskBrushTool = () =>
mouse.listen.canvas.left.onpaint.on(state.drawcb);
mouse.listen.canvas.right.onpaintstart.on(state.erasecb);
mouse.listen.canvas.right.onpaint.on(state.erasecb);
// Display Mask
setMask("neutral");
},
(state, opt) => {
// Clear Listeners
@ -63,6 +90,9 @@ const maskBrushTool = () =>
mouse.listen.canvas.left.onpaint.clear(state.drawcb);
mouse.listen.canvas.right.onpaintstart.clear(state.erasecb);
mouse.listen.canvas.right.onpaint.clear(state.erasecb);
// Hide Mask
setMask("none");
},
{
init: (state) => {
@ -81,10 +111,10 @@ const maskBrushTool = () =>
state.movecb = (evn) => {
if (evn.target.id === "overlayCanvas") {
// draw big translucent red blob cursor
// draw big translucent white blob cursor
ovCtx.beginPath();
ovCtx.arc(evn.x, evn.y, state.brushSize / 2, 0, 2 * Math.PI, true); // for some reason 4x on an arc is === to 8x on a line???
ovCtx.fillStyle = "#FF6A6A50";
ovCtx.fillStyle = "#FFFFFF50";
ovCtx.fill();
}
};

View file

@ -132,13 +132,16 @@ const toolbar = {
* Premade inputs for populating the context menus
*/
const _toolbar_input = {
checkbox: (state, dataKey, text) => {
checkbox: (state, dataKey, text, cb = null) => {
if (state[dataKey] === undefined) state[dataKey] = false;
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = state[dataKey];
checkbox.onchange = () => (state[dataKey] = checkbox.checked);
checkbox.onchange = () => {
state[dataKey] = checkbox.checked;
cb && cb();
};
const label = document.createElement("label");
label.appendChild(checkbox);

View file

@ -35,7 +35,7 @@ const guid = (size = 3) => {
.toString(16)
.substring(1);
};
// returns id of format 'aaaaaaaa'-'aaaa'-'aaaa'-'aaaa'-'aaaaaaaaaaaa'
// returns id of format 'aaaa'-'aaaa'-'aaaa' by default
let id = "";
for (var i = 0; i < size - 1; i++) id += s4() + "-";
id += s4();