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; position: absolute;
} }
/* Mask colors for mask inversion */
/* Filters are some magic acquired at https://codepen.io/sosuke/pen/Pjoqqp */
.maskPaintCanvas { .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 { .strokeText {

View file

@ -253,12 +253,18 @@ const dreamTool = () =>
mouse.listen.canvas.onmousemove.on(state.mousemovecb); mouse.listen.canvas.onmousemove.on(state.mousemovecb);
mouse.listen.canvas.left.onclick.on(state.dreamcb); mouse.listen.canvas.left.onclick.on(state.dreamcb);
mouse.listen.canvas.right.onclick.on(state.erasecb); mouse.listen.canvas.right.onclick.on(state.erasecb);
// Display Mask
setMask(state.invertMask ? "hold" : "clear");
}, },
(state, opt) => { (state, opt) => {
// Clear Listeners // Clear Listeners
mouse.listen.canvas.onmousemove.clear(state.mousemovecb); mouse.listen.canvas.onmousemove.clear(state.mousemovecb);
mouse.listen.canvas.left.onclick.clear(state.dreamcb); mouse.listen.canvas.left.onclick.clear(state.dreamcb);
mouse.listen.canvas.right.onclick.clear(state.erasecb); mouse.listen.canvas.right.onclick.clear(state.erasecb);
// Hide Mask
setMask("none");
}, },
{ {
init: (state) => { init: (state) => {
@ -286,7 +292,10 @@ const dreamTool = () =>
state.ctxmenu.invertMaskLabel = _toolbar_input.checkbox( state.ctxmenu.invertMaskLabel = _toolbar_input.checkbox(
state, state,
"invertMask", "invertMask",
"Invert Mask" "Invert Mask",
() => {
setMask(state.invertMask ? "hold" : "clear");
}
).label; ).label;
// Overmasking Slider // Overmasking Slider
@ -326,12 +335,18 @@ const img2imgTool = () =>
mouse.listen.canvas.onmousemove.on(state.mousemovecb); mouse.listen.canvas.onmousemove.on(state.mousemovecb);
mouse.listen.canvas.left.onclick.on(state.dreamcb); mouse.listen.canvas.left.onclick.on(state.dreamcb);
mouse.listen.canvas.right.onclick.on(state.erasecb); mouse.listen.canvas.right.onclick.on(state.erasecb);
// Display Mask
setMask(state.invertMask ? "hold" : "clear");
}, },
(state, opt) => { (state, opt) => {
// Clear Listeners // Clear Listeners
mouse.listen.canvas.onmousemove.clear(state.mousemovecb); mouse.listen.canvas.onmousemove.clear(state.mousemovecb);
mouse.listen.canvas.left.onclick.clear(state.dreamcb); mouse.listen.canvas.left.onclick.clear(state.dreamcb);
mouse.listen.canvas.right.onclick.clear(state.erasecb); mouse.listen.canvas.right.onclick.clear(state.erasecb);
// Hide mask
setMask("none");
}, },
{ {
init: (state) => { init: (state) => {
@ -361,7 +376,7 @@ const img2imgTool = () =>
const auxCtx = auxCanvas.getContext("2d"); const auxCtx = auxCanvas.getContext("2d");
if (state.keepBorderSize > 0) { if (state.keepBorderSize > 0) {
auxCtx.fillStyle = "#6A6AFF50"; auxCtx.fillStyle = "#6A6AFF7F";
auxCtx.fillRect(0, 0, state.keepBorderSize, bb.h); auxCtx.fillRect(0, 0, state.keepBorderSize, bb.h);
auxCtx.fillRect(0, 0, bb.w, state.keepBorderSize); auxCtx.fillRect(0, 0, bb.w, state.keepBorderSize);
auxCtx.fillRect( auxCtx.fillRect(
@ -403,7 +418,10 @@ const img2imgTool = () =>
state.ctxmenu.invertMaskLabel = _toolbar_input.checkbox( state.ctxmenu.invertMaskLabel = _toolbar_input.checkbox(
state, state,
"invertMask", "invertMask",
"Invert Mask" "Invert Mask",
() => {
setMask(state.invertMask ? "hold" : "clear");
}
).label; ).label;
// Inpaint Full Resolution Checkbox // 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) => { const _mask_brush_draw_callback = (evn, state) => {
if ( if (
(evn.initialTarget && evn.initialTarget.id === "overlayCanvas") || (evn.initialTarget && evn.initialTarget.id === "overlayCanvas") ||
(!evn.initialTarget && evn.target.id === "overlayCanvas") (!evn.initialTarget && evn.target.id === "overlayCanvas")
) { ) {
maskPaintCtx.globalCompositeOperation = "source-over"; maskPaintCtx.globalCompositeOperation = "source-over";
maskPaintCtx.strokeStyle = "#FF6A6A"; maskPaintCtx.strokeStyle = "black";
maskPaintCtx.lineWidth = state.brushSize; maskPaintCtx.lineWidth = state.brushSize;
maskPaintCtx.beginPath(); maskPaintCtx.beginPath();
@ -24,7 +48,7 @@ const _mask_brush_erase_callback = (evn, state) => {
(!evn.initialTarget && evn.target.id === "overlayCanvas") (!evn.initialTarget && evn.target.id === "overlayCanvas")
) { ) {
maskPaintCtx.globalCompositeOperation = "destination-out"; maskPaintCtx.globalCompositeOperation = "destination-out";
maskPaintCtx.strokeStyle = "#FFFFFFFF"; maskPaintCtx.strokeStyle = "black";
maskPaintCtx.lineWidth = state.brushSize; maskPaintCtx.lineWidth = state.brushSize;
maskPaintCtx.beginPath(); maskPaintCtx.beginPath();
@ -54,6 +78,9 @@ const maskBrushTool = () =>
mouse.listen.canvas.left.onpaint.on(state.drawcb); mouse.listen.canvas.left.onpaint.on(state.drawcb);
mouse.listen.canvas.right.onpaintstart.on(state.erasecb); mouse.listen.canvas.right.onpaintstart.on(state.erasecb);
mouse.listen.canvas.right.onpaint.on(state.erasecb); mouse.listen.canvas.right.onpaint.on(state.erasecb);
// Display Mask
setMask("neutral");
}, },
(state, opt) => { (state, opt) => {
// Clear Listeners // Clear Listeners
@ -63,6 +90,9 @@ const maskBrushTool = () =>
mouse.listen.canvas.left.onpaint.clear(state.drawcb); mouse.listen.canvas.left.onpaint.clear(state.drawcb);
mouse.listen.canvas.right.onpaintstart.clear(state.erasecb); mouse.listen.canvas.right.onpaintstart.clear(state.erasecb);
mouse.listen.canvas.right.onpaint.clear(state.erasecb); mouse.listen.canvas.right.onpaint.clear(state.erasecb);
// Hide Mask
setMask("none");
}, },
{ {
init: (state) => { init: (state) => {
@ -81,10 +111,10 @@ const maskBrushTool = () =>
state.movecb = (evn) => { state.movecb = (evn) => {
if (evn.target.id === "overlayCanvas") { if (evn.target.id === "overlayCanvas") {
// draw big translucent red blob cursor // draw big translucent white blob cursor
ovCtx.beginPath(); 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.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(); ovCtx.fill();
} }
}; };

View file

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

View file

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