From f92a7ff98ebd160f65e90cca554addc89061983a Mon Sep 17 00:00:00 2001 From: tim h Date: Sat, 19 Nov 2022 21:32:35 -0600 Subject: [PATCH 01/15] right-click erase is now an option --- index.html | 2 ++ js/index.js | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 0bb9163..5c12a62 100644 --- a/index.html +++ b/index.html @@ -74,6 +74,8 @@ onchange="changeScaleFactor()" />

+ +

diff --git a/js/index.js b/js/index.js index db9a7af..ebe7a54 100644 --- a/js/index.js +++ b/js/index.js @@ -88,6 +88,7 @@ var arbitraryImageData; var arbitraryImageBitmap; var arbitraryImageBase64; // seriously js cmon work with me here var placingArbitraryImage = false; // for when the user has loaded an existing image from their computer +var enableErasing = false; // accidental right-click erase if the user isn't trying to erase is a bad thing // info div, sometimes hidden let mouseXInfo = document.getElementById("mouseX"); @@ -427,7 +428,7 @@ function mouseDown(evt) { nextBox.h = basePixelCount * scaleFactor; drawTargets.push(nextBox); } - } else if (evt.button == 2 && !paintMode) { // right click, also gotta make sure mask blob isn't being used as it's visually inconsistent with behavior of erased region + } else if (evt.button == 2 && enableErasing && !paintMode) { // right click, also gotta make sure mask blob isn't being used as it's visually inconsistent with behavior of erased region // erase the canvas underneath the cursor, ctx = imgCanvas.getContext('2d'); if (snapToGrid) { @@ -723,11 +724,18 @@ function changePaintMode() { } function changeEraseMode() { + //TODO rename/refactor to make it more obvious this is just for painted masks eraseMode = document.getElementById("cbxErase").checked; clearTargetMask(); ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height); } +function changeEnableErasing() { + // yeah because this is for the image layer + enableErasing = document.getElementById("cbxEnableErasing").checked; + localStorage.setItem("enable_erase", enableErasing); +} + function changeSampler() { stableDiffusionData.sampler_index = document.getElementById("samplerSelect").value; localStorage.setItem("sampler", stableDiffusionData.sampler_index); @@ -902,6 +910,7 @@ function loadSettings() { var _mask_blur = localStorage.getItem("mask_blur") == null ? 0 : localStorage.getItem("mask_blur"); var _seed = localStorage.getItem("seed") == null ? -1 : localStorage.getItem("seed"); var _enable_hr = Boolean(localStorage.getItem("enable_hr") == (null || "false") ? false : localStorage.getItem("enable_hr")); + var _enable_erase = Boolean(localStorage.getItem("enable_erase") == (null || "false") ? false : localStorage.getItem("enable_erase")); // set the values into the UI document.getElementById("samplerSelect").value = String(_sampler); @@ -913,4 +922,5 @@ function loadSettings() { document.getElementById("maskBlur").value = Number(_mask_blur); document.getElementById("seed").value = Number(_seed); document.getElementById("cbxHRFix").checked = Boolean(_enable_hr); + document.getElementById("cbxEnableErasing").checked = Boolean(_enable_erase); } From ee5d0f8ac959e7ee1bde8bcd62ecb9a9c1b2cde9 Mon Sep 17 00:00:00 2001 From: tim h Date: Sat, 19 Nov 2022 21:39:18 -0600 Subject: [PATCH 02/15] =?UTF-8?q?=F0=9F=90=A0me=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb9db90..4100b47 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience - a big ol' 2560x1440 canvas for you to paint all over _(infinite canvas area planned, in //todo already)_ - inpainting/touchup blob - easily change samplers/steps/CFG/etc options for each dream summoned from the latent void - - right-click to erase output image under cursor + - optional right-click to erase output image under cursor - optional grid snapping for precision - optional overmasking for better seams between outpaints (suggested by [@lifeh2o](https://www.reddit.com/user/lifeh2o/overview) ([a](https://www.reddit.com/r/StableDiffusion/comments/ywf8np/i_made_a_completely_local_offline_opensource/iwl6s06/),[b](https://www.reddit.com/r/StableDiffusion/comments/ys9lhq/kollai_an_infinite_multiuser_canvas_running_on/ivzygwk/?context=3)) and i think it's a slick idea) - optional hi-res fix for blank/txt2img dreams which, if enabled, uses image width/height / 2 as firstpass size From 5b5b1fbfced1352aa8b156a2f14e0141d97d5965 Mon Sep 17 00:00:00 2001 From: tim h Date: Sat, 19 Nov 2022 22:10:20 -0600 Subject: [PATCH 03/15] font size/stroke visibility upgrade for us old folks --- css/index.css | 6 ++++++ js/index.js | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/css/index.css b/css/index.css index 119d6e8..013a073 100644 --- a/css/index.css +++ b/css/index.css @@ -144,4 +144,10 @@ .maskCanvasMonitor .overMaskCanvasMonitor .initImgCanvasMonitor { position: absolute; +} + +.strokeText { + -webkit-text-stroke: 1px #888; + font-size: 150%; + color: #000; } \ No newline at end of file diff --git a/js/index.js b/js/index.js index ebe7a54..655346e 100644 --- a/js/index.js +++ b/js/index.js @@ -130,6 +130,7 @@ function startup() { changeOverMask(); changeOverMaskPx(); changeHiResFix(); + changeEnableErasing(); document.getElementById("overlayCanvas").onmousemove = mouseMove; document.getElementById("overlayCanvas").onmousedown = mouseDown; document.getElementById("overlayCanvas").onmouseup = mouseUp; @@ -197,7 +198,7 @@ function imageAcceptReject(x, y, data) { div.style.top = parseInt(y + data.parameters.height) + "px"; div.style.width = "150px"; div.style.height = "50px"; - div.innerHTML = " of " + div.innerHTML = " of " document.getElementById("tempDiv").appendChild(div); document.getElementById("currentImgIndex").innerText = "1"; document.getElementById("totalImgIndex").innerText = totalImagesReturned; From 884a2b15376b24c78fafcc4c617c563ecdfa5ddf Mon Sep 17 00:00:00 2001 From: tim h Date: Sat, 19 Nov 2022 22:40:18 -0600 Subject: [PATCH 04/15] version bump and readfish --- README.md | 1 + index.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fb9db90..8c1130f 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com - 0.0.5 - import arbitrary image from user's machine, "auto" txt2img hires fix, Very Important "new image" button [3b7f4e3](https://github.com/zero01101/openOutpaint/commit/3b7f4e3759d0d1f3b38eba7249e5b58bc8162c75) - 0.0.5.1 - erase rendered imagery with right click, ensure webUI is running (thanks again [@Kalekki](https://github.com/Kalekki)! (https://github.com/zero01101/openOutpaint/pull/7)) [54577d4](https://github.com/zero01101/openOutpaint/commit/54577d4f15fd7d014aaf2471e0042b3c48735e9c) - 0.0.5.5 - highly attractive and functional floating control panel which will be extremely useful for infinite canvas, [@Kalekki](https://github.com/Kalekki) is literally the best ([11](https://github.com/zero01101/openOutpaint/pull/11)) [dac188d](https://github.com/zero01101/openOutpaint/commit/dac188dbfb086d3063f14b1a6a6a5b3add1aa5f5) +- 0.0.5.6 - _FINALLY_ the sliders update their values in realtime, a nice overall start on cleaning up my mess (thanks [@seijihariki](https://github.com/seijihariki)!) [d9fb87a](https://github.com/zero01101/openOutpaint/commit/d9fb87acec6653f19a9dac7777bd866782303ebc) ## what's with the fish? deep aquatic life is _fascinating_ so i went with something underwater for a default prompt which led to making an _"illustration of a bright orange fish, plain blue solid background"_ favicon which led to "ok then, fish is mascot" diff --git a/index.html b/index.html index 5758bb9..49ba674 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - openOutpaint 🐠 0.0.5.5 + openOutpaint 🐠 0.0.5.6 From a47a201fd5d624a4fcdea262adbb98b7fda46405 Mon Sep 17 00:00:00 2001 From: tim h Date: Sat, 19 Nov 2022 22:45:57 -0600 Subject: [PATCH 05/15] fishme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9afb653..d4c5778 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com - 0.0.5 - import arbitrary image from user's machine, "auto" txt2img hires fix, Very Important "new image" button [3b7f4e3](https://github.com/zero01101/openOutpaint/commit/3b7f4e3759d0d1f3b38eba7249e5b58bc8162c75) - 0.0.5.1 - erase rendered imagery with right click, ensure webUI is running (thanks again [@Kalekki](https://github.com/Kalekki)! (https://github.com/zero01101/openOutpaint/pull/7)) [54577d4](https://github.com/zero01101/openOutpaint/commit/54577d4f15fd7d014aaf2471e0042b3c48735e9c) - 0.0.5.5 - highly attractive and functional floating control panel which will be extremely useful for infinite canvas, [@Kalekki](https://github.com/Kalekki) is literally the best ([11](https://github.com/zero01101/openOutpaint/pull/11)) [dac188d](https://github.com/zero01101/openOutpaint/commit/dac188dbfb086d3063f14b1a6a6a5b3add1aa5f5) -- 0.0.5.6 - _FINALLY_ the sliders update their values in realtime, a nice overall start on cleaning up my mess (thanks [@seijihariki](https://github.com/seijihariki)!) [d9fb87a](https://github.com/zero01101/openOutpaint/commit/d9fb87acec6653f19a9dac7777bd866782303ebc) +- 0.0.5.6 - _FINALLY_ the sliders update their values in realtime, a nice overall start on cleaning up my mess (thanks [@seijihariki](https://github.com/seijihariki)!) ([14](https://github.com/zero01101/openOutpaint/pull/14)) [d9fb87a](https://github.com/zero01101/openOutpaint/commit/d9fb87acec6653f19a9dac7777bd866782303ebc) ## what's with the fish? deep aquatic life is _fascinating_ so i went with something underwater for a default prompt which led to making an _"illustration of a bright orange fish, plain blue solid background"_ favicon which led to "ok then, fish is mascot" From 2f416ad2b44da40dd12d73c40220e871186e3099 Mon Sep 17 00:00:00 2001 From: tim h Date: Sat, 19 Nov 2022 22:59:42 -0600 Subject: [PATCH 06/15] define: vanity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4c5778..271a514 100644 --- a/README.md +++ b/README.md @@ -142,4 +142,4 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com deep aquatic life is _fascinating_ so i went with something underwater for a default prompt which led to making an _"illustration of a bright orange fish, plain blue solid background"_ favicon which led to "ok then, fish is mascot" ![fullres fishy favicon](docs/05-openOutpaintFish.png) -the end 🐠 +~~the end~~ _𝒻𝒾𝓃_ 🐠 From 8a85e856fc781c459aa2f713a1de6a474eaa02f0 Mon Sep 17 00:00:00 2001 From: tim h Date: Sat, 19 Nov 2022 23:02:49 -0600 Subject: [PATCH 07/15] =?UTF-8?q?=E0=B2=A0=5F=E0=B2=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 271a514..11d6879 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com ## what's with the fish? deep aquatic life is _fascinating_ so i went with something underwater for a default prompt which led to making an _"illustration of a bright orange fish, plain blue solid background"_ favicon which led to "ok then, fish is mascot" + ![fullres fishy favicon](docs/05-openOutpaintFish.png) ~~the end~~ _𝒻𝒾𝓃_ 🐠 From 6d77e223fe368eb6d64c668a2c2e9cdea8239073 Mon Sep 17 00:00:00 2001 From: tim h Date: Sun, 20 Nov 2022 01:39:04 -0600 Subject: [PATCH 08/15] move royalty to their own section --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 11d6879..09398fc 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience - easily change samplers/steps/CFG/etc options for each dream summoned from the latent void - optional right-click to erase output image under cursor - optional grid snapping for precision - - optional overmasking for better seams between outpaints (suggested by [@lifeh2o](https://www.reddit.com/user/lifeh2o/overview) ([a](https://www.reddit.com/r/StableDiffusion/comments/ywf8np/i_made_a_completely_local_offline_opensource/iwl6s06/),[b](https://www.reddit.com/r/StableDiffusion/comments/ys9lhq/kollai_an_infinite_multiuser_canvas_running_on/ivzygwk/?context=3)) and i think it's a slick idea) + - optional overmasking for potentially better seams between outpaints and it _sorta_ works currently but it needs fixing - optional hi-res fix for blank/txt2img dreams which, if enabled, uses image width/height / 2 as firstpass size - import arbitrary images and superimpose on the canvas wherever you'd like ([extra fun with transparent .pngs!](#arbitrary_transparent)) - "temporary" monitors at the bottom to see exactly what mask/image you're feeding img2img, no i'm certainly not using them as actual imagedata sources or anything @@ -30,7 +30,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience ### notes - technically you can run it directly in browser as a bare `file://` protocol webpage but that's _really_ not recommended as you'll have to add `null` as an accepted domain to your `--cors-allow-origins` option which just seems like it's a visibly poor decision - - a deliciously simple launch script (thanks [@jasonmhead](https://github.com/jasonmhead)! (https://github.com/zero01101/openOutpaint/pull/1)) is included to pop up a teensy tiny python-based local webserver, however you may have to manually `chmod +x openOutpaint.sh` on mac/linux + - a deliciously simple launch script is included to pop up a teensy tiny python-based local webserver, however you may have to manually `chmod +x openOutpaint.sh` on mac/linux - the address http://127.0.0.1:3456 will be used as the host address for openOutpaint in the below quickstart; your local setup may use a different IP address or port. you can of course modify the included launch script to point at a different port than 3456 if desired, as well - if your scale factor is > 8 (generating an image larger than 512x512), try the "auto txt2img HR fix" option @@ -75,14 +75,14 @@ this is a completely vanilla javascript and html canvas outpainting convenience - [ ] add error handling for async/XHR POST in case of, yknow, errors - [x] image erase region in case you decide later that you're not too happy with earlier results (technically i guess you could just mask over the entire region you dislike but that's... bad) - [ ] controls for the rest of API-available options (e.g. ~~hires fix~~, inpaint fill modes, etc) -- [x] ~~save user-set option values to browser localstorage to persist your preferred, uh, preferences~~ (thanks [@Kalekki](https://github.com/Kalekki)! (https://github.com/zero01101/openOutpaint/pull/5)) +- [x] ~~save user-set option values to browser localstorage to persist your preferred, uh, preferences~~ - [ ] render progress spinner/bar -- [x] ~~smart crop downloaded image~~ (thanks again [@Kalekki](https://github.com/Kalekki)! (https://github.com/zero01101/openOutpaint/pull/2)) +- [x] ~~smart crop downloaded image~~ - [x] import external image and ~~scale/~~ superimpose at will on canvas for in/outpainting - [ ] scaling of imported arbitrary image before superimposition - [ ] "numpad" selector for determining how reticle is anchored against actual mouse cursor (currently works like a "5" [center] on the "numpad" paradigm) - [ ] discrete size control for mask and target reticle, discrete x/y axes for reticle -- [x] ~~floating/togglable menu leftnav bar with categorized/sensibly laid-out options~~ (holy crap thanks again [@Kalekki](https://github.com/Kalekki)! (https://github.com/zero01101/openOutpaint/pull/11)) +- [x] ~~floating/togglable menu leftnav bar with categorized/sensibly laid-out options~~ - [ ] infinite canvas - [ ] global undo/redo - [ ] inpainting sketch tools @@ -138,6 +138,11 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com - 0.0.5.5 - highly attractive and functional floating control panel which will be extremely useful for infinite canvas, [@Kalekki](https://github.com/Kalekki) is literally the best ([11](https://github.com/zero01101/openOutpaint/pull/11)) [dac188d](https://github.com/zero01101/openOutpaint/commit/dac188dbfb086d3063f14b1a6a6a5b3add1aa5f5) - 0.0.5.6 - _FINALLY_ the sliders update their values in realtime, a nice overall start on cleaning up my mess (thanks [@seijihariki](https://github.com/seijihariki)!) ([14](https://github.com/zero01101/openOutpaint/pull/14)) [d9fb87a](https://github.com/zero01101/openOutpaint/commit/d9fb87acec6653f19a9dac7777bd866782303ebc) +## collaborator credits πŸ‘‘ + - [@jasonmhead](https://github.com/jasonmhead) - [the most minimal launch script](https://github.com/zero01101/openOutpaint/pull/1) + - [@Kalekki](https://github.com/Kalekki) - all SORTS of awesome goodness, legit pull request hero: [what i was calling "smart crop"](https://github.com/zero01101/openOutpaint/pull/2),[localstorage](https://github.com/zero01101/openOutpaint/pull/5), [delightful floating UI](https://github.com/zero01101/openOutpaint/pull/11) + - [@lifeh2o](https://www.reddit.com/user/lifeh2o/overview) ([a](https://www.reddit.com/r/StableDiffusion/comments/ywf8np/i_made_a_completely_local_offline_opensource/iwl6s06/),[b](https://www.reddit.com/r/StableDiffusion/comments/ys9lhq/kollai_an_infinite_multiuser_canvas_running_on/ivzygwk/?context=3)) - overmasking concept that is still driving me crazy getting it to work right + ## what's with the fish? deep aquatic life is _fascinating_ so i went with something underwater for a default prompt which led to making an _"illustration of a bright orange fish, plain blue solid background"_ favicon which led to "ok then, fish is mascot" From 89624a2e8b0cb30085eef2f0eb557844d281d7fd Mon Sep 17 00:00:00 2001 From: tim h Date: Sun, 20 Nov 2022 01:47:21 -0600 Subject: [PATCH 09/15] =?UTF-8?q?update=20=F0=9F=90=A0me?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 09398fc..db6fbfa 100644 --- a/README.md +++ b/README.md @@ -134,13 +134,14 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com - 0.0.4.2 - pull requests (<3), downloaded images now have a timestamped name, css breakout because hopefully this will become halfway attractive enough to benefit from non-inline stylesheets [70ad4fe](https://github.com/zero01101/openOutpaint/commit/70ad4fe081bdbd507afc5af3cc2a4435924b66e3) - 0.0.4.3 - overmasking, settings saved to localstorage [fca2e01](https://github.com/zero01101/openOutpaint/commit/fca2e01b8a4ecfe3d062c4090d5886e1033e8f38) - 0.0.5 - import arbitrary image from user's machine, "auto" txt2img hires fix, Very Important "new image" button [3b7f4e3](https://github.com/zero01101/openOutpaint/commit/3b7f4e3759d0d1f3b38eba7249e5b58bc8162c75) -- 0.0.5.1 - erase rendered imagery with right click, ensure webUI is running (thanks again [@Kalekki](https://github.com/Kalekki)! (https://github.com/zero01101/openOutpaint/pull/7)) [54577d4](https://github.com/zero01101/openOutpaint/commit/54577d4f15fd7d014aaf2471e0042b3c48735e9c) -- 0.0.5.5 - highly attractive and functional floating control panel which will be extremely useful for infinite canvas, [@Kalekki](https://github.com/Kalekki) is literally the best ([11](https://github.com/zero01101/openOutpaint/pull/11)) [dac188d](https://github.com/zero01101/openOutpaint/commit/dac188dbfb086d3063f14b1a6a6a5b3add1aa5f5) -- 0.0.5.6 - _FINALLY_ the sliders update their values in realtime, a nice overall start on cleaning up my mess (thanks [@seijihariki](https://github.com/seijihariki)!) ([14](https://github.com/zero01101/openOutpaint/pull/14)) [d9fb87a](https://github.com/zero01101/openOutpaint/commit/d9fb87acec6653f19a9dac7777bd866782303ebc) +- 0.0.5.1 - erase rendered imagery with right click, ensure webUI is running [54577d4](https://github.com/zero01101/openOutpaint/commit/54577d4f15fd7d014aaf2471e0042b3c48735e9c) +- 0.0.5.5 - highly attractive and functional floating control panel which will be extremely useful for infinite canvas [dac188d](https://github.com/zero01101/openOutpaint/commit/dac188dbfb086d3063f14b1a6a6a5b3add1aa5f5) +- 0.0.5.6 - _FINALLY_ the sliders update their values in realtime, a nice overall start on cleaning up my mess [d9fb87a](https://github.com/zero01101/openOutpaint/commit/d9fb87acec6653f19a9dac7777bd866782303ebc) ## collaborator credits πŸ‘‘ - [@jasonmhead](https://github.com/jasonmhead) - [the most minimal launch script](https://github.com/zero01101/openOutpaint/pull/1) - - [@Kalekki](https://github.com/Kalekki) - all SORTS of awesome goodness, legit pull request hero: [what i was calling "smart crop"](https://github.com/zero01101/openOutpaint/pull/2),[localstorage](https://github.com/zero01101/openOutpaint/pull/5), [delightful floating UI](https://github.com/zero01101/openOutpaint/pull/11) + - [@Kalekki](https://github.com/Kalekki) - all SORTS of awesome goodness, legit pull request hero: [what i was calling "smart crop"](https://github.com/zero01101/openOutpaint/pull/2), [localstorage](https://github.com/zero01101/openOutpaint/pull/5), [right-click erase](https://github.com/zero01101/openOutpaint/pull/7), [delightful floating UI](https://github.com/zero01101/openOutpaint/pull/11) + - [@seijihariki](https://github.com/seijihariki) - realtime slider value updates, gracious code cleanup ([14](https://github.com/zero01101/openOutpaint/pull/14)) - [@lifeh2o](https://www.reddit.com/user/lifeh2o/overview) ([a](https://www.reddit.com/r/StableDiffusion/comments/ywf8np/i_made_a_completely_local_offline_opensource/iwl6s06/),[b](https://www.reddit.com/r/StableDiffusion/comments/ys9lhq/kollai_an_infinite_multiuser_canvas_running_on/ivzygwk/?context=3)) - overmasking concept that is still driving me crazy getting it to work right ## what's with the fish? From d85e54c5f19266d38d6747afd514d957afbf01df Mon Sep 17 00:00:00 2001 From: tim h Date: Sun, 20 Nov 2022 01:50:24 -0600 Subject: [PATCH 10/15] blblblblblblbl --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db6fbfa..5265f7e 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com - [@jasonmhead](https://github.com/jasonmhead) - [the most minimal launch script](https://github.com/zero01101/openOutpaint/pull/1) - [@Kalekki](https://github.com/Kalekki) - all SORTS of awesome goodness, legit pull request hero: [what i was calling "smart crop"](https://github.com/zero01101/openOutpaint/pull/2), [localstorage](https://github.com/zero01101/openOutpaint/pull/5), [right-click erase](https://github.com/zero01101/openOutpaint/pull/7), [delightful floating UI](https://github.com/zero01101/openOutpaint/pull/11) - [@seijihariki](https://github.com/seijihariki) - realtime slider value updates, gracious code cleanup ([14](https://github.com/zero01101/openOutpaint/pull/14)) - - [@lifeh2o](https://www.reddit.com/user/lifeh2o/overview) ([a](https://www.reddit.com/r/StableDiffusion/comments/ywf8np/i_made_a_completely_local_offline_opensource/iwl6s06/),[b](https://www.reddit.com/r/StableDiffusion/comments/ys9lhq/kollai_an_infinite_multiuser_canvas_running_on/ivzygwk/?context=3)) - overmasking concept that is still driving me crazy getting it to work right + - [@lifeh2o](https://www.reddit.com/user/lifeh2o/overview) - overmasking concept that is still driving me crazy getting it to work right ([a](https://www.reddit.com/r/StableDiffusion/comments/ywf8np/i_made_a_completely_local_offline_opensource/iwl6s06/),[b](https://www.reddit.com/r/StableDiffusion/comments/ys9lhq/kollai_an_infinite_multiuser_canvas_running_on/ivzygwk/?context=3)) ## what's with the fish? deep aquatic life is _fascinating_ so i went with something underwater for a default prompt which led to making an _"illustration of a bright orange fish, plain blue solid background"_ favicon which led to "ok then, fish is mascot" From ff68fcdedac04ed4e42ee840c18c4726ad1cf490 Mon Sep 17 00:00:00 2001 From: Kalekki Date: Sun, 20 Nov 2022 14:26:33 +0200 Subject: [PATCH 11/15] Mask erasing --- index.html | 7 ++++++- js/index.js | 32 +++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 511f4ab..5f9a5d3 100644 --- a/index.html +++ b/index.html @@ -69,8 +69,10 @@

+
@@ -90,6 +92,7 @@
+
@@ -108,7 +111,9 @@
- +
+ +

diff --git a/js/index.js b/js/index.js index 6f72437..16cca7c 100644 --- a/js/index.js +++ b/js/index.js @@ -92,6 +92,7 @@ var mouseX = 0; var mouseY = 0; var canvasX = 0; var canvasY = 0; +var heldButton = 0; var snapX = 0; var snapY = 0; var drawThis = {}; @@ -126,6 +127,7 @@ let canvasXInfo = document.getElementById("canvasX"); let canvasYInfo = document.getElementById("canvasY"); let snapXInfo = document.getElementById("snapX"); let snapYInfo = document.getElementById("snapY"); +let heldButtonInfo = document.getElementById("heldButton"); // canvases and related const ovCanvas = document.getElementById("overlayCanvas"); // where mouse cursor renders @@ -366,12 +368,14 @@ function mouseMove(evt) { const rect = ovCanvas.getBoundingClientRect() // not-quite pixel offset was driving me insane const canvasOffsetX = rect.left; const canvasOffsetY = rect.top; + heldButton = evt.buttons; mouseXInfo.innerText = mouseX = evt.clientX; mouseYInfo.innerText = mouseY = evt.clientY; canvasXInfo.innerText = canvasX = parseInt(evt.clientX - rect.left); canvasYInfo.innerText = canvasY = parseInt(evt.clientY - rect.top); snapXInfo.innerText = canvasX + snap(canvasX); snapYInfo.innerText = canvasY + snap(canvasY); + heldButtonInfo.innerText = heldButton; ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height); // clear out the previous mouse cursor if (placingArbitraryImage) { // ugh refactor so this isn't duplicated between arbitrary image and dream reticle modes @@ -423,6 +427,19 @@ function mouseMove(evt) { maskPaintCtx.lineJoin = maskPaintCtx.lineCap = 'round'; maskPaintCtx.stroke(); } + // Erase mask if right button is held + // no reason to have to tick a checkbox for this, more intuitive for both erases (mask and actual images) to just work on right click and inform the user about it + if (evt.buttons == 2) { + maskPaintCtx.globalCompositeOperation = 'destination-out'; + maskPaintCtx.beginPath(); + maskPaintCtx.strokeStyle = "#FFFFFFFF"; + maskPaintCtx.lineWidth = 8 * scaleFactor; + maskPaintCtx.moveTo(prevMouseX, prevMouseY); + maskPaintCtx.lineTo(mouseX, mouseY); + maskPaintCtx.lineJoin = maskPaintCtx.lineCap = 'round'; + maskPaintCtx.stroke(); + + } prevMouseX = mouseX; prevMouseY = mouseY; } @@ -458,13 +475,14 @@ function mouseDown(evt) { nextBox.h = basePixelCount * scaleFactor; drawTargets.push(nextBox); } - } else if (evt.button == 2 && enableErasing && !paintMode) { // right click, also gotta make sure mask blob isn't being used as it's visually inconsistent with behavior of erased region - // erase the canvas underneath the cursor, - ctx = imgCanvas.getContext('2d'); - if (snapToGrid) { - ctx.clearRect(canvasX + snap(canvasX) - ((basePixelCount * scaleFactor) / 2), canvasY + snap(canvasY) - ((basePixelCount * scaleFactor) / 2), basePixelCount * scaleFactor, basePixelCount * scaleFactor); - } else { - ctx.clearRect(canvasX - ((basePixelCount * scaleFactor) / 2), canvasY - ((basePixelCount * scaleFactor) / 2), basePixelCount * scaleFactor, basePixelCount * scaleFactor); + } else if (evt.button == 2){ + if(enableErasing && !paintMode) { // right click, also gotta make sure mask blob isn't being used as it's visually inconsistent with behavior of erased region + ctx = imgCanvas.getContext('2d'); + if (snapToGrid) { + ctx.clearRect(canvasX + snap(canvasX) - ((basePixelCount * scaleFactor) / 2), canvasY + snap(canvasY) - ((basePixelCount * scaleFactor) / 2), basePixelCount * scaleFactor, basePixelCount * scaleFactor); + } else { + ctx.clearRect(canvasX - ((basePixelCount * scaleFactor) / 2), canvasY - ((basePixelCount * scaleFactor) / 2), basePixelCount * scaleFactor, basePixelCount * scaleFactor); + } } } } From 8c9a5f527ea620927fded57741cf9e127cc17580 Mon Sep 17 00:00:00 2001 From: Kalekki Date: Sun, 20 Nov 2022 15:28:48 +0200 Subject: [PATCH 12/15] fix --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 5f9a5d3..d092732 100644 --- a/index.html +++ b/index.html @@ -69,10 +69,10 @@

-
- --> +
From ebf6900bfc767f44787066d70437b9e714eff1f4 Mon Sep 17 00:00:00 2001 From: Kalekki Date: Sun, 20 Nov 2022 18:24:17 +0200 Subject: [PATCH 13/15] make draggable class for possible future re-use --- css/index.css | 3 +++ index.html | 2 +- js/settingsbar.js | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/css/index.css b/css/index.css index 013a073..ee22326 100644 --- a/css/index.css +++ b/css/index.css @@ -55,6 +55,9 @@ z-index: 999; } +#draggable{ + cursor:move +} #DraggableTitleBar { z-index: 999; diff --git a/index.html b/index.html index 511f4ab..ad68c34 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@
-
openOutpaint 🐠
+
openOutpaint 🐠
diff --git a/js/settingsbar.js b/js/settingsbar.js index 9531643..e50228e 100644 --- a/js/settingsbar.js +++ b/js/settingsbar.js @@ -5,7 +5,10 @@ function dragElement(elmnt) { p2 = 0, p3 = 0, p4 = 0; - document.getElementById('DraggableTitleBar').onmousedown = dragMouseDown; + var draggableElements = document.getElementsByClassName('draggable'); + for (var i = 0; i < draggableElements.length; i++) { + draggableElements[i].onmousedown = dragMouseDown; + } function dragMouseDown(e) { e.preventDefault(); From 172e7dae0a66c20f14f9c49041b530e46bffce48 Mon Sep 17 00:00:00 2001 From: tim h Date: Sun, 20 Nov 2022 11:38:24 -0600 Subject: [PATCH 14/15] removed redundant overmask toggle overmaskpx = 0 effectively disables it anyway sets overmaskpx to a localstorage option removes moot "plain" mask monitor --- README.md | 2 +- index.html | 10 ++++------ js/index.js | 53 ++++++++++++++--------------------------------------- 3 files changed, 19 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 5265f7e..2031ee1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience - easily change samplers/steps/CFG/etc options for each dream summoned from the latent void - optional right-click to erase output image under cursor - optional grid snapping for precision - - optional overmasking for potentially better seams between outpaints and it _sorta_ works currently but it needs fixing + - optional overmasking for potentially better seams between outpaints and it _sorta_ works currently but it needs fixing - set overmask px value to 0 to disable the feature - optional hi-res fix for blank/txt2img dreams which, if enabled, uses image width/height / 2 as firstpass size - import arbitrary images and superimpose on the canvas wherever you'd like ([extra fun with transparent .pngs!](#arbitrary_transparent)) - "temporary" monitors at the bottom to see exactly what mask/image you're feeding img2img, no i'm certainly not using them as actual imagedata sources or anything diff --git a/index.html b/index.html index 511f4ab..ea18800 100644 --- a/index.html +++ b/index.html @@ -73,9 +73,7 @@

- -
- +
@@ -154,9 +152,9 @@
- -

lol ur browser sucks

-

+

lol ur browser sucks


diff --git a/js/index.js b/js/index.js index 6f72437..3a3abb3 100644 --- a/js/index.js +++ b/js/index.js @@ -107,9 +107,7 @@ var backupMaskChunk = null; var backupMaskX = null; var backupMaskY = null; var totalImagesReturned; -// var maskEdgePixels = {}; -var overMask = true; -var overMaskPx = 10; +var overMaskPx = 16; var drawTargets = []; // is this needed? i only draw the last one anyway... var dropTargets = []; // uhhh yeah similar to the above but for arbitrary dropped images var arbitraryImage; @@ -156,7 +154,6 @@ function startup() { changeSnapMode(); changeMaskBlur(); changeSeed(); - changeOverMask(); changeOverMaskPx(); changeHiResFix(); changeEnableErasing(); @@ -522,21 +519,18 @@ function mouseUp(evt) { //check if there's image data already there // console.log(downX + ":" + downY + " :: " + this.isCanvasBlank(downX, downY)); if (!isCanvasBlank(drawIt.x, drawIt.y, drawIt.w, drawIt.h, imgCanvas)) { - // img2img + // image exists, set up for img2img var mainCanvasCtx = document.getElementById("canvas").getContext("2d"); const imgChunk = mainCanvasCtx.getImageData(drawIt.x, drawIt.y, drawIt.w, drawIt.h); // imagedata object of the image being outpainted const imgChunkData = imgChunk.data; // imagedata.data object, a big inconvenient uint8clampedarray // these are the 3 mask monitors on the bottom of the page - var maskCanvas = document.getElementById("maskCanvasMonitor"); var initImgCanvas = document.getElementById("initImgCanvasMonitor"); var overMaskCanvas = document.getElementById("overMaskCanvasMonitor"); - overMaskCanvas.width = initImgCanvas.width = maskCanvas.width = target.w; - overMaskCanvas.height = initImgCanvas.height = maskCanvas.height = target.h; - var maskCanvasCtx = maskCanvas.getContext("2d"); + overMaskCanvas.width = initImgCanvas.width = target.w; //maskCanvas.width = target.w; + overMaskCanvas.height = initImgCanvas.height = target.h; //maskCanvas.height = target.h; var initImgCanvasCtx = initImgCanvas.getContext("2d"); var overMaskCanvasCtx = overMaskCanvas.getContext("2d"); // get blank pixels to use as mask - const maskImgData = maskCanvasCtx.createImageData(drawIt.w, drawIt.h); const initImgData = mainCanvasCtx.createImageData(drawIt.w, drawIt.h); const overMaskImgData = overMaskCanvasCtx.createImageData(drawIt.w, drawIt.h); // cover entire masks in black before adding masked areas @@ -545,12 +539,7 @@ function mouseUp(evt) { // l->r, top->bottom, R G B A pixel values in a big ol array // make a simple mask if (imgChunkData[i + 3] == 0) { // rgba pixel values, 4th one is alpha, if it's 0 there's "nothing there" in the image display canvas and its time to outpaint - maskImgData.data[i] = 255; // white mask gets painted over - maskImgData.data[i + 1] = 255; - maskImgData.data[i + 2] = 255; - maskImgData.data[i + 3] = 255; - - overMaskImgData.data[i] = 255; //lets just set this up now + overMaskImgData.data[i] = 255; // white mask gets painted over overMaskImgData.data[i + 1] = 255; overMaskImgData.data[i + 2] = 255; overMaskImgData.data[i + 3] = 255; @@ -561,15 +550,10 @@ function mouseUp(evt) { initImgData.data[i + 2] = 0; initImgData.data[i + 3] = 255; } else { // leave these pixels alone - maskImgData.data[i] = 0; // black mask gets ignored for in/outpainting - maskImgData.data[i + 1] = 0; - maskImgData.data[i + 2] = 0; - maskImgData.data[i + 3] = 255; // but it still needs an opaque alpha channel - - overMaskImgData.data[i] = 0; + overMaskImgData.data[i] = 0; // black mask gets ignored for in/outpainting overMaskImgData.data[i + 1] = 0; overMaskImgData.data[i + 2] = 0; - overMaskImgData.data[i + 3] = 255; + overMaskImgData.data[i + 3] = 255; // but it still needs an opaque alpha channel initImgData.data[i] = imgChunkData[i]; // put the original picture back in the painted area initImgData.data[i + 1] = imgChunkData[i + 1]; @@ -685,10 +669,6 @@ function mouseUp(evt) { const maskChunkData = maskChunk.data; for (let i = 0; i < maskChunkData.length; i += 4) { if (maskChunkData[i + 3] != 0) { - maskImgData.data[i] = 255; - maskImgData.data[i + 1] = 255; - maskImgData.data[i + 2] = 255; - maskImgData.data[i + 3] = 255; overMaskImgData.data[i] = 255; overMaskImgData.data[i + 1] = 255; overMaskImgData.data[i + 2] = 255; @@ -707,21 +687,17 @@ function mouseUp(evt) { } maskPaintCtx.putImageData(clearArea, drawIt.x, drawIt.y); // mask monitors - maskCanvasCtx.putImageData(maskImgData, 0, 0); - var maskBase64 = maskCanvas.toDataURL(); overMaskCanvasCtx.putImageData(overMaskImgData, 0, 0); // :pray: var overMaskBase64 = overMaskCanvas.toDataURL(); initImgCanvasCtx.putImageData(initImgData, 0, 0); var initImgBase64 = initImgCanvas.toDataURL(); - // img2img + // anyway all that to say NOW let's run img2img endpoint = "img2img"; - var selectedMask = overMask ? overMaskBase64 : maskBase64; - stableDiffusionData.mask = selectedMask; - // stableDiffusionData.mask = maskBase64; + stableDiffusionData.mask = overMaskBase64; stableDiffusionData.init_images = [initImgBase64]; // slightly more involved than txt2img } else { - // txt2img + // time to run txt2img endpoint = "txt2img"; // easy enough } @@ -782,12 +758,9 @@ function changeSeed() { localStorage.setItem("seed", stableDiffusionData.seed); } -function changeOverMask() { - overMask = document.getElementById("cbxOverMask").checked; -} - function changeOverMaskPx() { overMaskPx = document.getElementById("overMaskPx").value; + localStorage.setItem("overmask_px", overMaskPx); } function changeHiResFix() { @@ -912,12 +885,13 @@ function checkIfWebuiIsRunning() { } function loadSettings() { - // set default values if not set DEFAULTS + // set default values if not set var _sampler = localStorage.getItem("sampler") == null ? "DDIM" : localStorage.getItem("sampler"); var _mask_blur = localStorage.getItem("mask_blur") == null ? 0 : localStorage.getItem("mask_blur"); var _seed = localStorage.getItem("seed") == null ? -1 : localStorage.getItem("seed"); var _enable_hr = Boolean(localStorage.getItem("enable_hr") == (null || "false") ? false : localStorage.getItem("enable_hr")); var _enable_erase = Boolean(localStorage.getItem("enable_erase") == (null || "false") ? false : localStorage.getItem("enable_erase")); + var _overmask_px = localStorage.getItem("overmask_px") == null ? 0 : localStorage.getItem("overmask_px"); // set the values into the UI document.getElementById("samplerSelect").value = String(_sampler); @@ -925,4 +899,5 @@ function loadSettings() { document.getElementById("seed").value = Number(_seed); document.getElementById("cbxHRFix").checked = Boolean(_enable_hr); document.getElementById("cbxEnableErasing").checked = Boolean(_enable_erase); + document.getElementById("overMaskPx").value = Number(_overmask_px); } From 0906609da2fb85151217c180ecc7dc81c330e97b Mon Sep 17 00:00:00 2001 From: tim h Date: Sun, 20 Nov 2022 11:56:37 -0600 Subject: [PATCH 15/15] bump version, remove pointless checkbox --- README.md | 5 +++-- index.html | 11 ++++++----- js/index.js | 14 +++----------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 2031ee1..4069e6f 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ please do! kindly indicate your OS, browser, versions of both, any errors in dev ## known bugs :( - generated images display +1px on x/y during approve/reject state, doesn't affect output, just annoying - - erase mask is like entirely broken + - ~~erase mask is like entirely broken~~ - ~~odd-numbered scale factors don't snap correctly~~ - ~~arbitrary "pasted" images require clicking twice to place them and i _don't know why_ [(yes i do)](#terrible), just getting them to be arbitrarily placable was a giant pain because i'm not got the smarts~~ - selecting an aribtrary image by double-clicking it in the file picker can sometimes trigger a dream request that errors out if your file picker is "above" the canvas; i tried to alleviate that by temporarily removing the mouse(move/down/up) handlers for the canvas context on selection of a file, but i'm POSITIVE it's an improper solution and not quite sure if it's even fully effective @@ -137,10 +137,11 @@ imported a transparent clip of a [relatively famous happy lil kitty](https://com - 0.0.5.1 - erase rendered imagery with right click, ensure webUI is running [54577d4](https://github.com/zero01101/openOutpaint/commit/54577d4f15fd7d014aaf2471e0042b3c48735e9c) - 0.0.5.5 - highly attractive and functional floating control panel which will be extremely useful for infinite canvas [dac188d](https://github.com/zero01101/openOutpaint/commit/dac188dbfb086d3063f14b1a6a6a5b3add1aa5f5) - 0.0.5.6 - _FINALLY_ the sliders update their values in realtime, a nice overall start on cleaning up my mess [d9fb87a](https://github.com/zero01101/openOutpaint/commit/d9fb87acec6653f19a9dac7777bd866782303ebc) +- 0.0.5.7 - the majestic return of mask erasing, removed unnecessary overmask toggle [a96fd11](https://github.com/zero01101/openOutpaint/commit/a96fd116d750e38ce8982104ae5e5c966746fdc4) ## collaborator credits πŸ‘‘ - [@jasonmhead](https://github.com/jasonmhead) - [the most minimal launch script](https://github.com/zero01101/openOutpaint/pull/1) - - [@Kalekki](https://github.com/Kalekki) - all SORTS of awesome goodness, legit pull request hero: [what i was calling "smart crop"](https://github.com/zero01101/openOutpaint/pull/2), [localstorage](https://github.com/zero01101/openOutpaint/pull/5), [right-click erase](https://github.com/zero01101/openOutpaint/pull/7), [delightful floating UI](https://github.com/zero01101/openOutpaint/pull/11) + - [@Kalekki](https://github.com/Kalekki) - all SORTS of awesome goodness, legit pull request hero: [what i was calling "smart crop"](https://github.com/zero01101/openOutpaint/pull/2), [localstorage](https://github.com/zero01101/openOutpaint/pull/5), [right-click erase](https://github.com/zero01101/openOutpaint/pull/7), [delightful floating UI](https://github.com/zero01101/openOutpaint/pull/11), [mask erase fix](https://github.com/zero01101/openOutpaint/pull/17) - [@seijihariki](https://github.com/seijihariki) - realtime slider value updates, gracious code cleanup ([14](https://github.com/zero01101/openOutpaint/pull/14)) - [@lifeh2o](https://www.reddit.com/user/lifeh2o/overview) - overmasking concept that is still driving me crazy getting it to work right ([a](https://www.reddit.com/r/StableDiffusion/comments/ywf8np/i_made_a_completely_local_offline_opensource/iwl6s06/),[b](https://www.reddit.com/r/StableDiffusion/comments/ys9lhq/kollai_an_infinite_multiuser_canvas_running_on/ivzygwk/?context=3)) diff --git a/index.html b/index.html index 10087a1..854723e 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - openOutpaint 🐠 0.0.5.6 + openOutpaint 🐠 @@ -70,8 +70,8 @@
- -
+
@@ -109,9 +109,10 @@
-
+
- +
+ Alpha release v0.0.5.7

diff --git a/js/index.js b/js/index.js index 3e8e18e..f9684be 100644 --- a/js/index.js +++ b/js/index.js @@ -147,7 +147,6 @@ function startup() { drawBackground(); changeScaleFactor(); changePaintMode(); - changeEraseMode(); changeSampler(); changeSteps(); changeCfgScale(); @@ -435,7 +434,7 @@ function mouseMove(evt) { maskPaintCtx.lineTo(mouseX, mouseY); maskPaintCtx.lineJoin = maskPaintCtx.lineCap = 'round'; maskPaintCtx.stroke(); - + } prevMouseX = mouseX; prevMouseY = mouseY; @@ -472,8 +471,8 @@ function mouseDown(evt) { nextBox.h = basePixelCount * scaleFactor; drawTargets.push(nextBox); } - } else if (evt.button == 2){ - if(enableErasing && !paintMode) { // right click, also gotta make sure mask blob isn't being used as it's visually inconsistent with behavior of erased region + } else if (evt.button == 2) { + if (enableErasing && !paintMode) { // right click, also gotta make sure mask blob isn't being used as it's visually inconsistent with behavior of erased region ctx = imgCanvas.getContext('2d'); if (snapToGrid) { ctx.clearRect(canvasX + snap(canvasX) - ((basePixelCount * scaleFactor) / 2), canvasY + snap(canvasY) - ((basePixelCount * scaleFactor) / 2), basePixelCount * scaleFactor, basePixelCount * scaleFactor); @@ -740,13 +739,6 @@ function changePaintMode() { ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height); } -function changeEraseMode() { - //TODO rename/refactor to make it more obvious this is just for painted masks - eraseMode = document.getElementById("cbxErase").checked; - clearTargetMask(); - ovCtx.clearRect(0, 0, ovCanvas.width, ovCanvas.height); -} - function changeEnableErasing() { // yeah because this is for the image layer enableErasing = document.getElementById("cbxEnableErasing").checked;