diff --git a/css/icons.css b/css/icons.css
index 2cc159e..f962e4d 100644
--- a/css/icons.css
+++ b/css/icons.css
@@ -105,6 +105,12 @@
mask-image: url("../res/icons/paintbrush.svg");
}
+.ui.inline-icon.icon-slice::after,
+.ui.icon > .icon-slice {
+ -webkit-mask-image: url("../res/icons/slice.svg");
+ mask-image: url("../res/icons/slice.svg");
+}
+
.ui.inline-icon.icon-save::after,
.ui.icon > .icon-save {
-webkit-mask-image: url("../res/icons/save.svg");
diff --git a/index.html b/index.html
index aa1568c..5add2da 100644
--- a/index.html
+++ b/index.html
@@ -5,7 +5,7 @@
openOutpaint 🐠
-
+
@@ -434,7 +434,7 @@
-
+
@@ -468,7 +468,7 @@
src="js/ui/tool/generic.js?v=3e678e0"
type="text/javascript">
-
+
diff --git a/js/lib/util.js b/js/lib/util.js
index 2c59631..b41cf26 100644
--- a/js/lib/util.js
+++ b/js/lib/util.js
@@ -474,3 +474,55 @@ const makeElement = (
return el;
};
+
+/**
+ * Subtracts identical (or damn close) pixels from new dreams
+ * @param {HTMLCanvasElement} canvas
+ * @param {BoundingBox} bb
+ * @param {HTMLImageElement} bgImg
+ * @param {number}} blur
+ * @returns {HTMLCanvasElement}
+ */
+
+const subtractBackground = (canvas, bb, bgImg, blur = 0) => {
+ // set up temp canvases
+ const bgCanvas = document.createElement("canvas");
+ const fgCanvas = document.createElement("canvas");
+ const returnCanvas = document.createElement("canvas");
+ bgCanvas.width = fgCanvas.width = returnCanvas.width = bb.w;
+ bgCanvas.height = fgCanvas.height = returnCanvas.height = bb.h;
+ const bgCtx = bgCanvas.getContext("2d");
+ const fgCtx = fgCanvas.getContext("2d");
+ const returnCtx = returnCanvas.getContext("2d");
+ returnCtx.rect(0, 0, bb.w, bb.h);
+ returnCtx.fill();
+ // draw previous "background" image
+ bgCtx.drawImage(bgImg, 0, 0, bb.w, bb.h);
+ bgCtx.filter = "blur(" + blur + "px)";
+ // ... turn that into base64
+ const bgImgData = bgCtx.getImageData(0, 0, bb.w, bb.h);
+ // draw new image
+ fgCtx.drawImage(canvas, 0, 0);
+ const fgImgData = fgCtx.getImageData(0, 0, bb.w, bb.h);
+ // const blendImgData = blendCtx.getImageData(0, 0, bb.w, bb.h);
+ for (var i = 0; i < bgImgData.data.length; i += 4) {
+ var bgr = bgImgData.data[i];
+ var bgg = bgImgData.data[i + 1];
+ var bgb = bgImgData.data[i + 2];
+
+ var fgr = fgImgData.data[i];
+ var fgb = fgImgData.data[i + 1];
+ var fgd = fgImgData.data[i + 2];
+
+ const dr = Math.abs(bgr - fgr) > 10 ? fgr : 0;
+ const dg = Math.abs(bgg - fgb) > 10 ? fgb : 0;
+ const db = Math.abs(bgb - fgd) > 10 ? fgd : 0;
+
+ const pxChanged = dr > 0 && dg > 0 && db > 0;
+
+ fgImgData.data[i + 3] = pxChanged ? 255 : 0;
+ }
+ returnCtx.putImageData(fgImgData, 0, 0);
+
+ return returnCanvas;
+};
diff --git a/js/ui/tool/dream.js b/js/ui/tool/dream.js
index a06d2e7..0ddc38f 100644
--- a/js/ui/tool/dream.js
+++ b/js/ui/tool/dream.js
@@ -92,9 +92,19 @@ const generating = (val) => {
*
* @param {"txt2img" | "img2img"} endpoint Endpoint to send the request to
* @param {StableDiffusionRequest} request Stable diffusion request
+ * @param {BoundingBox} bb Optional: Generated image placement location
* @returns {Promise}
*/
-const _dream = async (endpoint, request) => {
+const _dream = async (endpoint, request, bb = null) => {
+ var bgImg = null;
+ if (
+ endpoint == "img2img" &&
+ bb &&
+ toolbar._current_tool.state.removeBackground
+ ) {
+ bgImg = uil.getVisible(bb, {includeBg: false});
+ }
+
const apiURL = `${host}${config.api.path}${endpoint}`;
// if script fields are populated add them to the request
var scriptName = document.getElementById("script-name-input").value;
@@ -169,6 +179,7 @@ const _dream = async (endpoint, request) => {
var returnData = {
images: data.images,
seeds: responseSubdata.all_seeds,
+ bgImg: bgImg,
};
return returnData;
};
@@ -442,7 +453,7 @@ const _generate = async (endpoint, request, bb, options = {}) => {
});
imageCollection.inputElement.appendChild(interruptButton);
- var dreamData = await _dream(endpoint, requestCopy);
+ var dreamData = await _dream(endpoint, requestCopy, bb);
images.push(...dreamData.images);
seeds.push(...dreamData.seeds);
stopDrawingStatus = true;
@@ -505,7 +516,7 @@ const _generate = async (endpoint, request, bb, options = {}) => {
// load the image data after defining the closure
img.src = "data:image/png;base64," + images[at];
img.addEventListener("load", () => {
- const canvas = document.createElement("canvas");
+ let canvas = document.createElement("canvas");
canvas.width = bb.w;
canvas.height = bb.h;
const ctx = canvas.getContext("2d");
@@ -519,6 +530,15 @@ const _generate = async (endpoint, request, bb, options = {}) => {
commands.runCommand("addLayer", "Added Layer", {});
}
+ if (
+ endpoint == "img2img" &&
+ toolbar._current_tool.state.removeBackground
+ ) {
+ //TODO SERIOUSLY CHECK FOR MORE THINGS HERE
+ canvas = subtractBackground(canvas, bb, dreamData.bgImg, 0);
+ // do something else too probably idunno
+ }
+
commands.runCommand("drawImage", "Image Dream", {
x: bb.x,
y: bb.y,
@@ -545,7 +565,7 @@ const _generate = async (endpoint, request, bb, options = {}) => {
addline(` + Model = ${modelAutoComplete.value}`);
addline(` + +Prompt = ${request.prompt}`);
addline(` + -Prompt = ${request.negative_prompt}`);
- addline(` + Styles = ${request.styles.join(", ")}`, false);
+ addline(` + Styles = ${request.styles.join(", ")}`, false);
commands.runCommand(
"drawImage",
@@ -1727,6 +1747,14 @@ const dreamTool = () =>
"icon-paintbrush"
).checkbox;
+ // Remove Identical/Background Pixels Checkbox
+ state.ctxmenu.removeBackgroundLabel = _toolbar_input.checkbox(
+ state,
+ "removeBackground",
+ "Remove Identical/BG Pixels",
+ "icon-slice"
+ ).checkbox;
+
// Overmasking Slider
state.ctxmenu.overMaskPxLabel = _toolbar_input.slider(
state,
@@ -1762,6 +1790,7 @@ const dreamTool = () =>
array.appendChild(state.ctxmenu.invertMaskLabel);
array.appendChild(state.ctxmenu.preserveMasksLabel);
//menu.appendChild(document.createElement("br"));
+ array.appendChild(state.ctxmenu.removeBackgroundLabel);
array.appendChild(state.ctxmenu.keepUnmaskedLabel);
menu.appendChild(array);
menu.appendChild(state.ctxmenu.keepUnmaskedBlurSlider);
@@ -2284,6 +2313,14 @@ const img2imgTool = () =>
"icon-box-select"
).checkbox;
+ // Remove Identical/Background Pixels Checkbox
+ state.ctxmenu.removeBackgroundLabel = _toolbar_input.checkbox(
+ state,
+ "removeBackground",
+ "Remove Identical/BG Pixels",
+ "icon-slice"
+ ).checkbox;
+
// Border Mask Size Slider
state.ctxmenu.borderMaskSlider = _toolbar_input.slider(
state,
@@ -2334,6 +2371,7 @@ const img2imgTool = () =>
array.appendChild(state.ctxmenu.snapToGridLabel);
array.appendChild(state.ctxmenu.invertMaskLabel);
array.appendChild(state.ctxmenu.preserveMasksLabel);
+ array.appendChild(state.ctxmenu.removeBackgroundLabel);
array.appendChild(state.ctxmenu.keepUnmaskedLabel);
menu.appendChild(array);
menu.appendChild(state.ctxmenu.keepUnmaskedBlurSlider);
diff --git a/pages/configuration.html b/pages/configuration.html
index 531147f..3f1aa2e 100644
--- a/pages/configuration.html
+++ b/pages/configuration.html
@@ -5,7 +5,7 @@
openOutpaint 🐠
-
+
diff --git a/res/icons/fish.svg b/res/icons/fish.svg
new file mode 100644
index 0000000..c5f5b72
--- /dev/null
+++ b/res/icons/fish.svg
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/res/icons/image-minus.svg b/res/icons/image-minus.svg
new file mode 100644
index 0000000..51eafa0
--- /dev/null
+++ b/res/icons/image-minus.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/res/icons/scissors.svg b/res/icons/scissors.svg
new file mode 100644
index 0000000..7c3526a
--- /dev/null
+++ b/res/icons/scissors.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/res/icons/slice.svg b/res/icons/slice.svg
new file mode 100644
index 0000000..77284dc
--- /dev/null
+++ b/res/icons/slice.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file