diff --git a/README.md b/README.md index 879c083..4c98f21 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience ## features +- [soft inpainting](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14208) support - SDXL "support"! (please check outpaint/inpaint fill types in the context menus and fiddle with denoising a LOT for img2img, it's touchy) - [now available as an extension for webUI!](https://github.com/zero01101/openOutpaint-webUI-extension) you can find it under the default "available" section in the webUI _extensions_ tab - **_NOTE: extension still requires `--api` flag in webui-user launch script_** diff --git a/css/icons.css b/css/icons.css index 08e7c00..214460d 100644 --- a/css/icons.css +++ b/css/icons.css @@ -196,3 +196,9 @@ -webkit-mask-image: url("../res/icons/clipboard-list.svg"); mask-image: url("../res/icons/clipboard-list.svg"); } + +.ui.inline-icon.icon-squircle::after, +.ui.icon > .icon-squircle { + -webkit-mask-image: url("../res/icons/squircle.svg"); + mask-image: url("../res/icons/squircle.svg"); +} diff --git a/index.html b/index.html index c26dda0..94ef95e 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ openOutpaint 🐠 - + @@ -186,12 +186,12 @@
- -
+
--> - v20240127.001 + v20240302.001
- + @@ -560,7 +560,7 @@ - + - + @@ -584,7 +584,7 @@ - + diff --git a/js/extensions.js b/js/extensions.js index b4e8448..410e00d 100644 --- a/js/extensions.js +++ b/js/extensions.js @@ -5,6 +5,7 @@ const extensions = { // alwaysOnScriptsData: {}, alwaysOnScripts: false, + // softInpaintingEnabled: false, //??? controlNetEnabled: false, controlNetActive: false, controlNetReferenceActive: false, @@ -53,6 +54,7 @@ const extensions = { console.warn("[index] Failed to fetch extensions"); console.warn(e); } + this.checkForSoftInpainting(); this.checkForDynamicPrompts(); this.checkForControlNet( controlNetModelAutoComplete, @@ -64,6 +66,11 @@ const extensions = { //checkForSAG(); //?? }, + async checkForSoftInpainting() { + this.alwaysOnScripts = true; + //TODO implement, inpaint/img2img only + }, + async checkForDynamicPrompts() { if ( this.enabledExtensions.filter((e) => e.includes("dynamic prompts")) diff --git a/js/index.js b/js/index.js index c1442d9..b5ccf7a 100644 --- a/js/index.js +++ b/js/index.js @@ -170,7 +170,7 @@ function startup() { changeRefinerEnabled(); changeHiResFix(); changeHiResSquare(); - changeRestoreFaces(); + // changeRestoreFaces(); changeSyncCursorSize(); changeControlNetExtension(); changeControlNetReference(); @@ -1558,7 +1558,7 @@ function loadSettings() { document.getElementById("maskBlur").value = Number(_mask_blur); document.getElementById("seed").value = Number(_seed); document.getElementById("cbxHRFix").checked = Boolean(_enable_hr); - document.getElementById("cbxRestoreFaces").checked = Boolean(_restore_faces); + // document.getElementById("cbxRestoreFaces").checked = Boolean(_restore_faces); document.getElementById("cbxSyncCursorSize").checked = Boolean(_sync_cursor_size); document.getElementById("hrFixScale").value = Number(_hrfix_scale); diff --git a/js/ui/tool/dream.js b/js/ui/tool/dream.js index 7938e0b..5d23d73 100644 --- a/js/ui/tool/dream.js +++ b/js/ui/tool/dream.js @@ -1227,6 +1227,7 @@ const dream_generate_callback = async (bb, resolution, state) => { if (extensions.dynamicPromptsEnabled) { addDynamicPromptsToAlwaysOnScripts(state); } + // and controlnet stuff if ( extensions.controlNetActive && !isCanvasBlank(0, 0, bb.w, bb.h, visibleCanvas) @@ -1358,10 +1359,15 @@ const dream_generate_callback = async (bb, resolution, state) => { // add dynamic prompts stuff if it's enabled if (extensions.dynamicPromptsEnabled) { addDynamicPromptsToAlwaysOnScripts(state); - } + } // and controlnet stuff if (extensions.controlNetActive) { addControlNetToAlwaysOnScripts(state, initCanvas, maskCanvas); } + // and soft inpainting + if (state.softInpaint) { + addSoftInpaintingToAlwaysOnScripts(state); + // TODO build always on scripts entry for soft inpaint + } if (extensions.alwaysOnScripts) { // check again just to be sure because i'm an idiot? // addControlNetToAlwaysOnScripts(state); @@ -1588,6 +1594,7 @@ const dream_img2img_callback = (bb, resolution, state) => { if (extensions.dynamicPromptsEnabled) { addDynamicPromptsToAlwaysOnScripts(state); } + // and controlnet if (extensions.controlNetActive) { if (extensions.controlNetReferenceActive) { addControlNetToAlwaysOnScripts( @@ -1599,6 +1606,12 @@ const dream_img2img_callback = (bb, resolution, state) => { addControlNetToAlwaysOnScripts(state, null, null); // //WTF??? } } + // and soft inpainting + if (state.softInpaint) { + addSoftInpaintingToAlwaysOnScripts(state); + // TODO build always on scripts entry for soft inpaint + } + if (extensions.alwaysOnScripts) { // check again just to be sure because i'm an idiot? // addControlNetToAlwaysOnScripts(state); @@ -2160,6 +2173,153 @@ const dreamTool = () => state.ctxmenu.carveThresholdSlider.classList.add("invisible"); } + // soft inpainting checkbox - arg 0 + state.ctxmenu.softInpaintLabel = _toolbar_input.checkbox( + state, + "openoutpaint/img2img-softinpaint", + "softInpaint", + "Soft Inpainting", + "icon-squircle", + () => { + if (state.softInpaint) { + extensions.checkForSoftInpainting(); + state.ctxmenu.softInpaintScheduleBiasSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.remove( + "invisible" + ); + // state.ctxmenu.softInpaintSliderLinebreak.classList.add( + // "invisible" + // ); + } else { + state.ctxmenu.softInpaintScheduleBiasSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.add( + "invisible" + ); + // state.ctxmenu.softInpaintSliderLinebreak.classList.remove( + // "invisible" + // ); + } + } + ).checkbox; + + // soft inpainting schedule bias - arg 1, def 1 + state.ctxmenu.softInpaintScheduleBiasSlider = _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintschedulebias", + "softInpaintScheduleBias", + "Schedule Bias", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + + // soft inpainting preservation strength - arg 2, def 0.5 + state.ctxmenu.softInpaintPreservationStrengthSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintpreservationstrength", + "softInpaintPreservationStrength", + "Preservation Strength", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + + // soft inpainting transition contrast boost - arg 3, def 4 + state.ctxmenu.softInpaintTransitionContrastBoostSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpainttransitioncontrastboost", + "softInpaintTransitionContrastBoost", + "Transition Contrast Boost", + { + min: 0, + max: 32, + step: 0.5, + textStep: 0.01, + } + ).slider; + + //0.5 2 + + // soft inpainting mask influence - arg 4, def 0 + state.ctxmenu.softInpaintMaskInfluenceSlider = _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintmaskinfluence", + "softInpaintMaskInfluence", + "Mask Influence", + { + min: 0, + max: 1, + step: 0.1, + textStep: 0.01, + } + ).slider; + + // soft inpainting difference threshold - arg 5, def 0.5 + state.ctxmenu.softInpaintDifferenceThresholdSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintdifferencethreshold", + "softInpaintDifferenceThreshold", + "Difference Threshold", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + + // soft inpainting difference contrast - arg 6, def 2 + state.ctxmenu.softInpaintDifferenceContrastSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintdifferenceContrast", + "softInpaintDifferenceContrast", + "Difference Contrast", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + menu.appendChild(state.ctxmenu.cursorSizeSlider); const array = document.createElement("div"); array.classList.add("checkbox-array"); @@ -2170,6 +2330,7 @@ const dreamTool = () => //menu.appendChild(document.createElement("br")); array.appendChild(state.ctxmenu.keepUnmaskedLabel); array.appendChild(state.ctxmenu.removeBackgroundLabel); + // array.appendChild(state.ctxmenu.softInpaintLabel); //TODO: if (global.controlnetAPI) { //but figure out how to update the UI after doing so // never mind i think i'm using an extension menu instead // array.appendChild(state.ctxmenu.controlNetLabel); @@ -2178,6 +2339,14 @@ const dreamTool = () => menu.appendChild(state.ctxmenu.keepUnmaskedBlurSlider); menu.appendChild(state.ctxmenu.carveBlurSlider); menu.appendChild(state.ctxmenu.carveThresholdSlider); + // menu.appendChild(state.ctxmenu.softInpaintScheduleBiasSlider); + // menu.appendChild(state.ctxmenu.softInpaintPreservationStrengthSlider); + // menu.appendChild( + // state.ctxmenu.softInpaintTransitionContrastBoostSlider + // ); + // menu.appendChild(state.ctxmenu.softInpaintMaskInfluenceSlider); + // menu.appendChild(state.ctxmenu.softInpaintDifferenceThresholdSlider); + // menu.appendChild(state.ctxmenu.softInpaintDifferenceContrastSlider); // menu.appendChild(state.ctxmenu.keepUnmaskedBlurSliderLinebreak); // menu.appendChild(state.ctxmenu.preserveMasksLabel); // menu.appendChild(document.createElement("br")); @@ -2198,6 +2367,48 @@ const dreamTool = () => state.ctxmenu.carveBlurSlider.classList.add("invisible"); state.ctxmenu.carveThresholdSlider.classList.add("invisible"); } + + if ( + localStorage.getItem("openoutpaint/img2img-softinpaint") == "true" + ) { + state.ctxmenu.softInpaintScheduleBiasSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.remove( + "invisible" + ); + } else { + state.ctxmenu.softInpaintScheduleBiasSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.add( + "invisible" + ); + } }, shortcut: "D", } @@ -2717,7 +2928,7 @@ const img2imgTool = () => ).slider; // Border Mask Gradient Checkbox - state.ctxmenu.borderMaskGradientCheckbox = _toolbar_input.checkbox( + state.ctxmenu.borderMaskGradientLabel = _toolbar_input.checkbox( state, "openoutpaint/img2img-gradient", "gradient", @@ -2745,6 +2956,153 @@ const img2imgTool = () => } ).checkbox; + // soft inpainting checkbox - arg 0 + state.ctxmenu.softInpaintLabel = _toolbar_input.checkbox( + state, + "openoutpaint/img2img-softinpaint", + "softInpaint", + "Soft Inpainting", + "icon-squircle", + () => { + if (state.softInpaint) { + extensions.checkForSoftInpainting(); + state.ctxmenu.softInpaintScheduleBiasSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.remove( + "invisible" + ); + // state.ctxmenu.softInpaintSliderLinebreak.classList.add( + // "invisible" + // ); + } else { + state.ctxmenu.softInpaintScheduleBiasSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.add( + "invisible" + ); + // state.ctxmenu.softInpaintSliderLinebreak.classList.remove( + // "invisible" + // ); + } + } + ).checkbox; + + // soft inpainting schedule bias - arg 1, def 1 + state.ctxmenu.softInpaintScheduleBiasSlider = _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintschedulebias", + "softInpaintScheduleBias", + "Schedule Bias", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + + // soft inpainting preservation strength - arg 2, def 0.5 + state.ctxmenu.softInpaintPreservationStrengthSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintpreservationstrength", + "softInpaintPreservationStrength", + "Preservation Strength", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + + // soft inpainting transition contrast boost - arg 3, def 4 + state.ctxmenu.softInpaintTransitionContrastBoostSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpainttransitioncontrastboost", + "softInpaintTransitionContrastBoost", + "Transition Contrast Boost", + { + min: 0, + max: 32, + step: 0.5, + textStep: 0.01, + } + ).slider; + + //0.5 2 + + // soft inpainting mask influence - arg 4, def 0 + state.ctxmenu.softInpaintMaskInfluenceSlider = _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintmaskinfluence", + "softInpaintMaskInfluence", + "Mask Influence", + { + min: 0, + max: 1, + step: 0.1, + textStep: 0.01, + } + ).slider; + + // soft inpainting difference threshold - arg 5, def 0.5 + state.ctxmenu.softInpaintDifferenceThresholdSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintdifferencethreshold", + "softInpaintDifferenceThreshold", + "Difference Threshold", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + + // soft inpainting difference contrast - arg 6, def 2 + state.ctxmenu.softInpaintDifferenceContrastSlider = + _toolbar_input.slider( + state, + "openoutpaint/img2img-softinpaintdifferenceContrast", + "softInpaintDifferenceContrast", + "Difference Contrast", + { + min: 0, + max: 8, + step: 0.25, + textStep: 0.01, + } + ).slider; + // Border Mask Size Slider state.ctxmenu.borderMaskSlider = _toolbar_input.slider( state, @@ -2847,10 +3205,19 @@ const img2imgTool = () => array.appendChild(state.ctxmenu.preserveMasksLabel); array.appendChild(state.ctxmenu.keepUnmaskedLabel); array.appendChild(state.ctxmenu.removeBackgroundLabel); + array.appendChild(state.ctxmenu.softInpaintLabel); menu.appendChild(array); menu.appendChild(state.ctxmenu.keepUnmaskedBlurSlider); menu.appendChild(state.ctxmenu.carveBlurSlider); menu.appendChild(state.ctxmenu.carveThresholdSlider); + menu.appendChild(state.ctxmenu.softInpaintScheduleBiasSlider); + menu.appendChild(state.ctxmenu.softInpaintPreservationStrengthSlider); + menu.appendChild( + state.ctxmenu.softInpaintTransitionContrastBoostSlider + ); + menu.appendChild(state.ctxmenu.softInpaintMaskInfluenceSlider); + menu.appendChild(state.ctxmenu.softInpaintDifferenceThresholdSlider); + menu.appendChild(state.ctxmenu.softInpaintDifferenceContrastSlider); // menu.appendChild(state.ctxmenu.keepUnmaskedBlurSliderLinebreak); menu.appendChild(state.ctxmenu.inpaintTypeSelect); menu.appendChild(state.ctxmenu.denoisingStrengthSlider); @@ -2858,7 +3225,7 @@ const img2imgTool = () => const btnArray2 = document.createElement("div"); btnArray2.classList.add("checkbox-array"); btnArray2.appendChild(state.ctxmenu.fullResolutionLabel); - btnArray2.appendChild(state.ctxmenu.borderMaskGradientCheckbox); + btnArray2.appendChild(state.ctxmenu.borderMaskGradientLabel); menu.appendChild(btnArray2); menu.appendChild(state.ctxmenu.borderMaskSlider); menu.appendChild(state.ctxmenu.eagerGenerateCountLabel); @@ -2878,6 +3245,48 @@ const img2imgTool = () => state.ctxmenu.carveBlurSlider.classList.add("invisible"); state.ctxmenu.carveThresholdSlider.classList.add("invisible"); } + + if ( + localStorage.getItem("openoutpaint/img2img-softinpaint") == "true" + ) { + state.ctxmenu.softInpaintScheduleBiasSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.remove( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.remove( + "invisible" + ); + } else { + state.ctxmenu.softInpaintScheduleBiasSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintMaskInfluenceSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceContrastSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintDifferenceThresholdSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintPreservationStrengthSlider.classList.add( + "invisible" + ); + state.ctxmenu.softInpaintTransitionContrastBoostSlider.classList.add( + "invisible" + ); + } }, shortcut: "I", } @@ -2888,11 +3297,28 @@ const sendSeed = (seed) => { }; function buildAlwaysOnScripts(state) { + //todo make sure soft inpainting works + if (extensions.alwaysOnScripts) { state.alwayson_scripts = {}; } } +function addSoftInpaintingToAlwaysOnScripts(state) { + if (extensions.alwaysOnScripts) { + state.alwayson_scripts["Soft Inpainting"] = {}; + state.alwayson_scripts["Soft Inpainting"].args = [ + state.softInpaint, + state.softInpaintScheduleBias, + state.softInpaintPreservationStrength, + state.softInpaintTransitionContrastBoost, + state.softInpaintMaskInfluence, + state.softInpaintDifferenceThreshold, + state.softInpaintDifferenceContrast, + ]; + } +} + function addDynamicPromptsToAlwaysOnScripts(state) { if (extensions.dynamicPromptsEnabled) { state.alwayson_scripts[extensions.dynamicPromptsAlwaysonScriptName] = {}; diff --git a/pages/configuration.html b/pages/configuration.html index 1a241e4..87e300f 100644 --- a/pages/configuration.html +++ b/pages/configuration.html @@ -5,7 +5,7 @@ openOutpaint 🐠 - + diff --git a/res/icons/squircle.svg b/res/icons/squircle.svg new file mode 100644 index 0000000..8eea9d8 --- /dev/null +++ b/res/icons/squircle.svg @@ -0,0 +1 @@ + \ No newline at end of file