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:
parent
fe4b50cb8d
commit
fe2ebec569
5 changed files with 79 additions and 11 deletions
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue