Skip to content

Commit

Permalink
Merge pull request #239 from zero01101/controlnet_inpaint
Browse files Browse the repository at this point in the history
controlnet inpaint
  • Loading branch information
zero01101 authored Jul 9, 2023
2 parents 899c2cb + 0e687f8 commit 071ed03
Show file tree
Hide file tree
Showing 9 changed files with 637 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience
- arbitrary dream reticle size - draw the rectangle of your dreams
- an [effectively infinite](https://github.com/zero01101/openOutpaint/pull/108), resizable, scalable canvas for you to paint all over
- **_NOTE: v0.0.10 introduces a new "camera control" modifier key - hold [`CTRL`] and use the scrollwheel to zoom (scroll the wheel or use the two-finger vertical gesture on, uh, modern touchpads) and pan (hold the scrollwheel button, or if you don't have one, left-click button) around the canvas_**
- extremely limited, janky support for a shockingly restrictive list of A1111 extensions including controlnet inpainting for legitimately [magic](https://github.com/Mikubill/sd-webui-controlnet/discussions/1464) [promptless inpainting](https://github.com/Mikubill/sd-webui-controlnet/discussions/1143) and [outpainting](https://github.com/Mikubill/sd-webui-controlnet/discussions/1597)
- a very nicely functional and familiar layer system
- save, load, import, and export workspaces - includes all your layers, history, canvas size, you name it!
- inpainting/touchup mask brush
Expand Down
6 changes: 6 additions & 0 deletions css/icons.css
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@
mask-image: url("../res/icons/slice.svg");
}

.ui.inline-icon.icon-joystick::after,
.ui.icon > .icon-joystick {
-webkit-mask-image: url("../res/icons/joystick.svg");
mask-image: url("../res/icons/joystick.svg");
}

.ui.inline-icon.icon-save::after,
.ui.icon > .icon-save {
-webkit-mask-image: url("../res/icons/save.svg");
Expand Down
4 changes: 2 additions & 2 deletions defaultscripts.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"scriptValues": "[false, false, \"positive\", \"comma\", 2]"
},
"X/Y/Z plot": {
"titleText": "Params:\nx_type (int): index of axis type (see below) //def: 3\nx_values (mixed, str) //def: \"0.00-0.99 [4]\"\ny_type (int) //def: 4\ny_values (mixed, str) //def: \"5-30 [4]\"\nz_type (int) //def: 6\nz_values (mixed, str) //def: \"2.5-12.5 [4]\"\ndraw_legend (bool): return grid of all images //def: false\ninclude_lone_images (bool): return individual images //def: true\ninclude_subgrids (bool) //def: false\nno_fixed_seeds (bool): use different seeds for each picture //def: false\nmargin_size (int): grid margins in px //def: 2\n\nAvailable axis types:\n0: Nothing\n1: Seed\n2: Var. seed\n3: Var. strength\n4: Steps\n5: Hires steps (txt2img only)\n6: CFG Scale\n7: Image CFG Scale (img2img with instructPix2Pix only)\n8: Prompt S/R\n9: Prompt order\n10: Sampler (txt2img only)\n11: Sampler (img2img only)\n12: Checkpoint Name\n13: Sigma Churn\n14: Sigma min\n15: Sigma max\n16: Sigma noise\n17: Eta\n18: Clip skip\n19: Denoising\n20: Hires upscaler (txt2img only)\n21: Cond. Image Mask Weight (img2img only)\n22: VAE\n23: Styles\n24: UniPC Order\n25: Face Restore",
"scriptValues": "[3, \"0.00-0.99 [4]\", 4, \"5-30 [4]\", 6, \"2.5-12.5 [4]\", false, true, false, false, 2]"
"titleText": "Params:\nx_type (int): index of axis type (see below) //def: 3\nx_values (mixed, str) //def: \"0.00-0.99 [4]\"\nx_values_dropdown (NOIDEA) //def: \"\"\ny_type (int) //def: 4\ny_values (mixed, str) //def: \"5-30 [4]\"\ny_values_dropdown (NOIDEA) //def: \"\"\nz_type (int) //def: 6\nz_values (mixed, str) //def: \"2.5-12.5 [4]\"\nz_values_dropdown (NOIDEA) //def: \"\"\ndraw_legend (bool): return grid of all images //def: false\ninclude_lone_images (bool): return individual images //def: true\ninclude_subgrids (bool) //def: false\nno_fixed_seeds (bool): use different seeds for each picture //def: false\nmargin_size (int): grid margins in px //def: 2\n\nAvailable axis types:\n0: Nothing\n1: Seed\n2: Var. seed\n3: Var. strength\n4: Steps\n5: Hires steps (txt2img only)\n6: CFG Scale\n7: Image CFG Scale (img2img with instructPix2Pix only)\n8: Prompt S/R\n9: Prompt order\n10: Sampler (txt2img only)\n11: Sampler (img2img only)\n12: Checkpoint Name\n13: Negative Guidance minimum sigma\n14: Sigma Churn\n15: Sigma min\n16: Sigma max\n17: Sigma noise\n18: Schedule Type\n19: Schedule min sigma\n20:Schedule max sigma\n21: Schedule rho\n22: Eta\n23: Clip skip\n24: Denoising\n25: Hires upscaler (txt2img only)\n26: Cond. Image Mask Weight (img2img only)\n27: VAE\n23: Styles\n28: UniPC Order\n29: Face Restore\n30: Token merging ratio\n31: Token merging ratio hi-res",
"scriptValues": "[3, \"0.00-0.99 [4]\", \"\", 4, \"5-30 [4]\", \"\", 6, \"2.5-12.5 [4]\", \"\", false, true, false, false, 2]"
}
}
}
57 changes: 51 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<title>openOutpaint 🐠</title>
<!-- CSS Variables -->
<link href="css/colors.css?v=f732f19" rel="stylesheet" />
<link href="css/icons.css?v=a8ec439" rel="stylesheet" />
<link href="css/icons.css?v=e6f94af" rel="stylesheet" />

<link href="css/index.css?v=aaad3e5" rel="stylesheet" />
<link href="css/layers.css?v=92c0352" rel="stylesheet" />
Expand Down Expand Up @@ -143,10 +143,12 @@
id="seed"
onchange="changeSeed()"
min="-1"
max="9999999999"
max="99999999999999999999"
value="-1"
step="1" />
<br />
<label>Lora:</label>
<div id="lora-ac-select"></div>
<input type="checkbox" id="cbxHRFix" onchange="changeHiResFix()" />
<label for="cbxHRFix">Apply Txt2Img HRfix</label>
<br />
Expand Down Expand Up @@ -195,7 +197,48 @@
step="1"
onchange="changeMaskBlur()" />
</div>

<!-- Extensions section -->
<button type="button" class="collapsible">Extensions</button>
<div class="content">
<input
type="checkbox"
id="cbxDynPrompts"
onchange="changeDynamicPromptsExtension()"
disabled="disabled" />
<label for="cbxDynPrompts">Dynamic Prompts</label>
<br />
<input
type="checkbox"
id="cbxControlNet"
onchange="changeControlNetExtension()"
disabled="disabled" />
<label for="cbxControlNet">ControlNet In/Outpainting</label>
<br class="controlnetElement" />
<label id="cnModuleLabel" class="controlnetElement">
Preprocessor
</label>
<div id="controlNetModule-ac-select" class="controlnetElement"></div>
<label id="cnModelLabel" class="controlnetElement">Model</label>
<div id="controlNetModel-ac-select" class="controlnetElement"></div>
<label id="cnControlLabel" class="controlnetElement">
Control Mode
</label>
<select id="controlNetMode-select" class="controlnetElement">
<option value="Balanced">balanced</option>
<option value="My prompt is more important">+prompt</option>
<option value="ControlNet is more important">+CN</option>
</select>
<br />
<label id="cnResizeLabel" class="controlnetElement">
Resize Mode
</label>
<select id="controlNetResize-select" class="controlnetElement">
<option value="Just Resize">resize</option>
<option value="Crop and Resize">+crop</option>
<option value="Resize and Fill">+fill</option>
</select>
<!-- <div id="referenceStyleFidelity" class="controlnetElement"></div> -->
</div>
<!-- Save/load image section -->
<button type="button" class="collapsible">Save/Upscaling</button>
<div class="content">
Expand Down Expand Up @@ -244,7 +287,8 @@
<br />
<span id="version">
<a href="https://github.com/zero01101/openOutpaint" target="_blank">
Alpha release v0.0.15.3 (20230410.001)
<s>Alpha release v0.0.16</s>
v20230708.001
</a>
<br />
<a
Expand Down Expand Up @@ -441,6 +485,7 @@
<!-- Basics -->
<script src="js/global.js?v=ac30d16" type="text/javascript"></script>
<script src="js/defaults.js?v=5b06818" type="text/javascript"></script>
<script src="js/extensions.js?v=fec7579" type="text/javascript"></script>

<!-- Base Libs -->
<script src="js/lib/util.js?v=379aef7" type="text/javascript"></script>
Expand All @@ -466,7 +511,7 @@

<!-- Content -->
<script src="js/prompt.js?v=7a1c68c" type="text/javascript"></script>
<script src="js/index.js?v=e10fcb1" type="text/javascript"></script>
<script src="js/index.js?v=31d52e7" type="text/javascript"></script>

<script
src="js/ui/floating/history.js?v=4f29db4"
Expand All @@ -480,7 +525,7 @@
src="js/ui/tool/generic.js?v=3e678e0"
type="text/javascript"></script>

<script src="js/ui/tool/dream.js?v=97e4806" type="text/javascript"></script>
<script src="js/ui/tool/dream.js?v=45b8acd" type="text/javascript"></script>
<script
src="js/ui/tool/maskbrush.js?v=e9bd0eb"
type="text/javascript"></script>
Expand Down
160 changes: 160 additions & 0 deletions js/extensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/**
* Extensions helper thing or class or whatever
*/

const extensions = {
// alwaysOnScriptsData: {},
alwaysOnScripts: false,
controlNetEnabled: false,
controlNetActive: false,
selectedControlNetModel: null,
selectedControlNetModule: null,
dynamicPromptsEnabled: false,
dynamicPromptsActive: false,
dynamicPromptsAlwaysonScriptName: null, //GRUMBLE GRUMBLE
enabledExtensions: [],
controlNetModels: null,
controlNetModules: null,

async getExtensions(
controlNetModelAutoComplete,
controlNetModuleAutoComplete
) {
const allowedExtensions = [
"controlnet",
// "none",
// "adetailer", // no API, can't verify available models
"dynamic prompts", //seriously >:( why put version in the name, now i have to fuzzy match it - just simply enabled or not? no API but so so good
//"segment anything", // ... API lets me get model but not processor?!?!?!
//"self attention guidance", // no API but useful, just enabled button, scale and threshold sliders?
];
// check http://127.0.0.1:7860/sdapi/v1/scripts for extensions
// if any of the allowed extensions are found, add them to the list
var url = document.getElementById("host").value + "/sdapi/v1/scripts";
try {
const response = await fetch(url);
const data = await response.json();
// enable checkboxes for extensions based on existence in data
data.img2img
.filter((extension) => {
return allowedExtensions.some((allowedExtension) => {
return extension.toLowerCase().includes(allowedExtension);
});
})
.forEach((extension) => {
this.enabledExtensions.push(extension);
});
} catch (e) {
console.warn("[index] Failed to fetch extensions");
console.warn(e);
}
this.checkForDynamicPrompts();
this.checkForControlNet(
controlNetModelAutoComplete,
controlNetModuleAutoComplete
);
//checkForSAM(); //or inpaintAnything or something i dunno
//checkForADetailer(); //? this one seems iffy
//checkForSAG(); //??
},

async checkForDynamicPrompts() {
if (
this.enabledExtensions.filter((e) => e.includes("dynamic prompts"))
.length > 0
) {
// Dynamic Prompts found, enable checkbox
this.alwaysOnScripts = true;
this.dynamicPromptsAlwaysonScriptName =
this.enabledExtensions[
this.enabledExtensions.findIndex((e) => e.includes("dynamic prompts"))
];
// this.alwaysOnScriptsData[this.dynamicPromptsAlwaysonScriptName] = {};
this.dynamicPromptsEnabled = true;
document.getElementById("cbxDynPrompts").disabled = false;
}
// basically param 0 is true for on, false for off, that's it
},

async checkForControlNet(
controlNetModelAutoComplete,
controlNetModuleAutoComplete
) {
var url = document.getElementById("host").value + "/controlnet/version";

try {
const response = await fetch(url);
const data = await response.json();

if (
data.version > 0 &&
this.enabledExtensions.filter((e) => e.includes("controlnet")).length >
0
) {
// ControlNet found
this.alwaysOnScripts = true;
this.controlNetEnabled = true;
document.getElementById("cbxControlNet").disabled = false;
// ok cool so now we can get the models and modules
this.getModels(controlNetModelAutoComplete);
this.getModules(controlNetModuleAutoComplete);
}
} catch (e) {
// ??
global.controlnetAPI = false;
}
},
async getModels(controlNetModelAutoComplete) {
// only worry about inpaint models for now
var url = document.getElementById("host").value + "/controlnet/model_list";

try {
const response = await fetch(url);
const data = await response.json();

this.controlNetModels = data.model_list;
} catch (e) {
console.warn("[extensions] Failed to fetch controlnet models");
console.warn(e);
}

let opt = null;
opt = this.controlNetModels
.filter((m) => m.includes("inpaint"))
.map((option) => ({
name: option,
value: option,
}));

controlNetModelAutoComplete.options = opt;
},
async getModules(controlNetModuleAutoComplete) {
const allowedModules = ["reference", "inpaint"];
var url = document.getElementById("host").value + "/controlnet/module_list";

try {
const response = await fetch(url);
const data = await response.json();

this.controlNetModules = data;
} catch (e) {
console.warn("[extensions] Failed to fetch controlnet modules");
console.warn(e);
}

let opt = null;
opt = this.controlNetModules.module_list
.filter((m) => m.includes("inpaint")) // why is there just "inpaint" in the modules if it's not in the ui
.map((option) => ({
name: option,
value: option,
}));

opt.push({
name: "inpaint_global_harmonious",
value: "inpaint_global_harmonious", // WTF WHY IS THIS ONE NOT LISTED IN MODULES BUT DISTINCT IN THE API CALL?!?!?!??!??! it is slightly different from "inpaint" from what i can tell
});

controlNetModuleAutoComplete.options = opt;
},
};
Loading

0 comments on commit 071ed03

Please sign in to comment.