Merge branch 'main' into edit_utils
Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
commit
096d8770f2
6 changed files with 940 additions and 1085 deletions
19
.prettierrc.json
Normal file
19
.prettierrc.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"arrowParens": "always",
|
||||
"bracketSameLine": true,
|
||||
"bracketSpacing": false,
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"insertPragma": false,
|
||||
"jsxSingleQuote": false,
|
||||
"printWidth": 80,
|
||||
"proseWrap": "preserve",
|
||||
"quoteProps": "as-needed",
|
||||
"requirePragma": false,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": true,
|
||||
"vueIndentScriptAndStyle": false
|
||||
}
|
14
README.md
14
README.md
|
@ -17,11 +17,12 @@ 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 - set overmask px value to 0 to disable the feature
|
||||
- optional overmasking for potentially better seams between outpaints - 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
|
||||
- saves your preferences to browser localstorage for maximum convenience
|
||||
- undo/redo
|
||||
|
||||
## operation
|
||||
|
||||
|
@ -69,7 +70,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience
|
|||
- [ ] lots and lots of readme updates (ongoing)
|
||||
- [ ] comment basically everything that isn't self documenting (ongoing)
|
||||
- [ ] CHORE: refactor all the duplicated JS code (ongoing, guaranteed to get worse before it gets better)
|
||||
- [x] overmask seam of img2img - BUG: it kinda sucks currently, just moves the seam instead of fixing it, i want to try to gradient-fade the edge but filter = 'blur(Ypx)' is _awful_ for this and my remedial per-pixel loops crash the browser because i am the embodiment of inefficiency
|
||||
- [x] overmask seam of img2img ~~BUG: it kinda sucks currently, just moves the seam instead of fixing it, i want to try to gradient-fade the edge but filter = 'blur(Ypx)' is awful for this and my remedial per-pixel loops crash the browser because i am the embodiment of inefficiency~~
|
||||
- [x] split out CSS to its own file (remedial cleanup task)
|
||||
- [x] ability to blank/new canvas without making the user refresh the page because that's pretty janky
|
||||
- [ ] add error handling for async/XHR POST in case of, yknow, errors
|
||||
|
@ -84,7 +85,7 @@ this is a completely vanilla javascript and html canvas outpainting convenience
|
|||
- [ ] 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~~
|
||||
- [ ] infinite canvas
|
||||
- [ ] global undo/redo
|
||||
- [x] ~~global undo/redo~~
|
||||
- [ ] inpainting sketch tools
|
||||
- [ ] split out JS to separation-of-concerns individual files (oh no)
|
||||
- [x] ~~something actually similar to a "user interface", preferably visually pleasant and would make my mom say "well that makes sense" if she looked at it~~
|
||||
|
@ -138,12 +139,15 @@ 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 [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)
|
||||
- 0.0.6 - absolutely brilliant undo/redo system, logical and straightforward enough to the point where even i can understand what it's doing [25681b3](https://github.com/zero01101/openOutpaint/commit/25681b3a83bbd7a1d1b3e675f26f141692d77c79)
|
||||
- 0.0.6.1 - finally think i've got overmasking working better with a bit of "humanization" to the automated masks, please play around with it and see if it's any better or just sucks in general [8002772](https://github.com/zero01101/openOutpaint/commit/8002772ee6aa4b2f5b544af82cb6d545cf81368f)
|
||||
|
||||
## 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), [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))
|
||||
- [@seijihariki](https://github.com/seijihariki) - [realtime slider value updates, gracious code cleanup](https://github.com/zero01101/openOutpaint/pull/14), [blessed undo/redo](https://github.com/zero01101/openOutpaint/pull/21)
|
||||
- [@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)) [possible betterness?](https://github.com/zero01101/openOutpaint/commit/8002772ee6aa4b2f5b544af82cb6d545cf81368f)
|
||||
|
||||
|
||||
## 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"
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
<span id="snapY"></span><br />
|
||||
<label for="heldButton">Mouse button:</label>
|
||||
<span id="heldButton"></span><br />
|
||||
<span id="version">Alpha release v0.0.5.7</span>
|
||||
<span id="version">Alpha release v0.0.6.1</span>
|
||||
<br />
|
||||
<hr>
|
||||
</div>
|
||||
|
|
|
@ -40,9 +40,7 @@ const commands = {
|
|||
try {
|
||||
run(copy, state);
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`Error while running command '${name}' with options:`
|
||||
);
|
||||
console.warn(`Error while running command '${name}' with options:`);
|
||||
console.warn(copy);
|
||||
console.warn(e);
|
||||
return;
|
||||
|
@ -120,12 +118,7 @@ commands.createCommand(
|
|||
},
|
||||
(state) => {
|
||||
// Clear destination area
|
||||
state.context.clearRect(
|
||||
state.box.x,
|
||||
state.box.y,
|
||||
state.box.w,
|
||||
state.box.h
|
||||
);
|
||||
state.context.clearRect(state.box.x, state.box.y, state.box.w, state.box.h);
|
||||
// Undo
|
||||
state.context.drawImage(state.original, state.box.x, state.box.y);
|
||||
}
|
||||
|
|
603
js/index.js
603
js/index.js
|
@ -5,11 +5,11 @@ window.onload = startup;
|
|||
|
||||
var stableDiffusionData = {
|
||||
//includes img2img data but works for txt2img just fine
|
||||
prompt: '',
|
||||
negative_prompt: '',
|
||||
prompt: "",
|
||||
negative_prompt: "",
|
||||
seed: -1,
|
||||
cfg_scale: null,
|
||||
sampler_index: 'DDIM',
|
||||
sampler_index: "DDIM",
|
||||
steps: null,
|
||||
denoising_strength: 1,
|
||||
mask_blur: 0,
|
||||
|
@ -17,7 +17,7 @@ var stableDiffusionData = {
|
|||
width: 512,
|
||||
height: 512,
|
||||
n_iter: null, // batch count
|
||||
mask: '',
|
||||
mask: "",
|
||||
init_images: [],
|
||||
inpaint_full_res: false,
|
||||
inpainting_fill: 2,
|
||||
|
@ -89,9 +89,9 @@ var blockNewImages = false;
|
|||
var returnedImages;
|
||||
var imageIndex = 0;
|
||||
var tmpImgXYWH = {};
|
||||
var host = '';
|
||||
var url = '/sdapi/v1/';
|
||||
var endpoint = 'txt2img';
|
||||
var host = "";
|
||||
var url = "/sdapi/v1/";
|
||||
var endpoint = "txt2img";
|
||||
var frameX = 512;
|
||||
var frameY = 512;
|
||||
var prevMouseX = 0;
|
||||
|
@ -124,29 +124,32 @@ 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
|
||||
var marchOffset = 0;
|
||||
var marching = false;
|
||||
var marchCoords = {};
|
||||
|
||||
// info div, sometimes hidden
|
||||
let mouseXInfo = document.getElementById('mouseX');
|
||||
let mouseYInfo = document.getElementById('mouseY');
|
||||
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');
|
||||
let mouseXInfo = document.getElementById("mouseX");
|
||||
let mouseYInfo = document.getElementById("mouseY");
|
||||
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
|
||||
const ovCtx = ovCanvas.getContext('2d');
|
||||
const tgtCanvas = document.getElementById('targetCanvas'); // where "box" gets drawn before dream happens
|
||||
const tgtCtx = tgtCanvas.getContext('2d');
|
||||
const maskPaintCanvas = document.getElementById('maskPaintCanvas'); // where masking brush gets painted
|
||||
const maskPaintCtx = maskPaintCanvas.getContext('2d');
|
||||
const tempCanvas = document.getElementById('tempCanvas'); // where select/rejects get superimposed temporarily
|
||||
const tempCtx = tempCanvas.getContext('2d');
|
||||
const imgCanvas = document.getElementById('canvas'); // where dreams go
|
||||
const imgCtx = imgCanvas.getContext('2d');
|
||||
const bgCanvas = document.getElementById('backgroundCanvas'); // gray bg grid
|
||||
const bgCtx = bgCanvas.getContext('2d');
|
||||
const ovCanvas = document.getElementById("overlayCanvas"); // where mouse cursor renders
|
||||
const ovCtx = ovCanvas.getContext("2d");
|
||||
const tgtCanvas = document.getElementById("targetCanvas"); // where "box" gets drawn before dream happens
|
||||
const tgtCtx = tgtCanvas.getContext("2d");
|
||||
const maskPaintCanvas = document.getElementById("maskPaintCanvas"); // where masking brush gets painted
|
||||
const maskPaintCtx = maskPaintCanvas.getContext("2d");
|
||||
const tempCanvas = document.getElementById("tempCanvas"); // where select/rejects get superimposed temporarily
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
const imgCanvas = document.getElementById("canvas"); // where dreams go
|
||||
const imgCtx = imgCanvas.getContext("2d");
|
||||
const bgCanvas = document.getElementById("backgroundCanvas"); // gray bg grid
|
||||
const bgCtx = bgCanvas.getContext("2d");
|
||||
|
||||
function startup() {
|
||||
checkIfWebuiIsRunning();
|
||||
|
@ -165,10 +168,10 @@ function startup() {
|
|||
changeOverMaskPx();
|
||||
changeHiResFix();
|
||||
changeEnableErasing();
|
||||
document.getElementById('overlayCanvas').onmousemove = mouseMove;
|
||||
document.getElementById('overlayCanvas').onmousedown = mouseDown;
|
||||
document.getElementById('overlayCanvas').onmouseup = mouseUp;
|
||||
document.getElementById('scaleFactor').value = scaleFactor;
|
||||
document.getElementById("overlayCanvas").onmousemove = mouseMove;
|
||||
document.getElementById("overlayCanvas").onmousedown = mouseDown;
|
||||
document.getElementById("overlayCanvas").onmouseup = mouseUp;
|
||||
document.getElementById("scaleFactor").value = scaleFactor;
|
||||
}
|
||||
|
||||
function drop(imageParams) {
|
||||
|
@ -180,14 +183,14 @@ function drop(imageParams) {
|
|||
}
|
||||
|
||||
function writeArbitraryImage(img, x, y) {
|
||||
commands.runCommand('drawImage', {
|
||||
commands.runCommand("drawImage", {
|
||||
x,
|
||||
y,
|
||||
image: img,
|
||||
});
|
||||
blockNewImages = false;
|
||||
placingArbitraryImage = false;
|
||||
document.getElementById('preloadImage').files = null;
|
||||
document.getElementById("preloadImage").files = null;
|
||||
}
|
||||
|
||||
function dream(x, y, prompt) {
|
||||
|
@ -196,12 +199,7 @@ function dream(x, y, prompt) {
|
|||
tmpImgXYWH.w = prompt.width;
|
||||
tmpImgXYWH.h = prompt.height;
|
||||
console.log(
|
||||
'dreaming to ' +
|
||||
host +
|
||||
url +
|
||||
endpoint +
|
||||
':\r\n' +
|
||||
JSON.stringify(prompt)
|
||||
"dreaming to " + host + url + endpoint + ":\r\n" + JSON.stringify(prompt)
|
||||
);
|
||||
postData(prompt).then((data) => {
|
||||
returnedImages = data.images;
|
||||
|
@ -213,19 +211,19 @@ function dream(x, y, prompt) {
|
|||
}
|
||||
|
||||
async function postData(promptData) {
|
||||
this.host = document.getElementById('host').value;
|
||||
this.host = document.getElementById("host").value;
|
||||
// Default options are marked with *
|
||||
const response = await fetch(this.host + this.url + this.endpoint, {
|
||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||
mode: 'cors', // no-cors, *cors, same-origin
|
||||
cache: 'default', // *default, no-cache, reload, force-cache, only-if-cached
|
||||
credentials: 'same-origin', // include, *same-origin, omit
|
||||
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
||||
mode: "cors", // no-cors, *cors, same-origin
|
||||
cache: "default", // *default, no-cache, reload, force-cache, only-if-cached
|
||||
credentials: "same-origin", // include, *same-origin, omit
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
redirect: 'follow', // manual, *follow, error
|
||||
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
||||
redirect: "follow", // manual, *follow, error
|
||||
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
||||
body: JSON.stringify(promptData), // body data type must match "Content-Type" header
|
||||
});
|
||||
return response.json(); // parses JSON response into native JavaScript objects
|
||||
|
@ -235,28 +233,28 @@ function imageAcceptReject(x, y, data) {
|
|||
const img = new Image();
|
||||
img.onload = function () {
|
||||
tempCtx.drawImage(img, x, y); //imgCtx for actual image, tmp for... holding?
|
||||
var div = document.createElement('div');
|
||||
div.id = 'veryTempDiv';
|
||||
div.style.position = 'absolute';
|
||||
div.style.left = parseInt(x) + 'px';
|
||||
div.style.top = parseInt(y + data.parameters.height) + 'px';
|
||||
div.style.width = '150px';
|
||||
div.style.height = '50px';
|
||||
var div = document.createElement("div");
|
||||
div.id = "veryTempDiv";
|
||||
div.style.position = "absolute";
|
||||
div.style.left = parseInt(x) + "px";
|
||||
div.style.top = parseInt(y + data.parameters.height) + "px";
|
||||
div.style.width = "150px";
|
||||
div.style.height = "50px";
|
||||
div.innerHTML =
|
||||
'<button onclick="prevImg(this)"><</button><button onclick="nextImg(this)">></button><span class="strokeText" id="currentImgIndex"></span><span class="strokeText"> of </span><span class="strokeText" id="totalImgIndex"></span><button onclick="accept(this)">Y</button><button onclick="reject(this)">N</button>';
|
||||
document.getElementById('tempDiv').appendChild(div);
|
||||
document.getElementById('currentImgIndex').innerText = '1';
|
||||
document.getElementById('totalImgIndex').innerText =
|
||||
totalImagesReturned;
|
||||
document.getElementById("tempDiv").appendChild(div);
|
||||
document.getElementById("currentImgIndex").innerText = "1";
|
||||
document.getElementById("totalImgIndex").innerText = totalImagesReturned;
|
||||
};
|
||||
// set the image displayed as the first regardless of batch size/count
|
||||
imageIndex = 0;
|
||||
// load the image data after defining the closure
|
||||
img.src = 'data:image/png;base64,' + returnedImages[imageIndex];
|
||||
img.src = "data:image/png;base64," + returnedImages[imageIndex];
|
||||
}
|
||||
|
||||
function accept(evt) {
|
||||
// write image to imgcanvas
|
||||
marching = false;
|
||||
clearBackupMask();
|
||||
placeImage();
|
||||
removeChoiceButtons();
|
||||
|
@ -266,6 +264,7 @@ function accept(evt) {
|
|||
|
||||
function reject(evt) {
|
||||
// remove image entirely
|
||||
marching = false;
|
||||
restoreBackupMask();
|
||||
clearBackupMask();
|
||||
clearTargetMask();
|
||||
|
@ -300,7 +299,7 @@ function changeImg(forward) {
|
|||
img.onload = function () {
|
||||
tempCtx.drawImage(img, tmpImgXYWH.x, tmpImgXYWH.y); //imgCtx for actual image, tmp for... holding?
|
||||
};
|
||||
var tmpIndex = document.getElementById('currentImgIndex');
|
||||
var tmpIndex = document.getElementById("currentImgIndex");
|
||||
if (forward) {
|
||||
imageIndex++;
|
||||
} else {
|
||||
|
@ -308,11 +307,11 @@ function changeImg(forward) {
|
|||
}
|
||||
tmpIndex.innerText = imageIndex + 1;
|
||||
// load the image data after defining the closure
|
||||
img.src = 'data:image/png;base64,' + returnedImages[imageIndex]; //TODO need way to dream batches and select from results
|
||||
img.src = "data:image/png;base64," + returnedImages[imageIndex]; //TODO need way to dream batches and select from results
|
||||
}
|
||||
|
||||
function removeChoiceButtons(evt) {
|
||||
const element = document.getElementById('veryTempDiv');
|
||||
const element = document.getElementById("veryTempDiv");
|
||||
element.remove();
|
||||
tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
}
|
||||
|
@ -352,7 +351,7 @@ function clearPaintedMask() {
|
|||
function placeImage() {
|
||||
const img = new Image();
|
||||
img.onload = function () {
|
||||
commands.runCommand('drawImage', {
|
||||
commands.runCommand("drawImage", {
|
||||
x: tmpImgXYWH.x,
|
||||
y: tmpImgXYWH.y,
|
||||
image: img,
|
||||
|
@ -361,7 +360,7 @@ function placeImage() {
|
|||
returnedImages = null;
|
||||
};
|
||||
// load the image data after defining the closure
|
||||
img.src = 'data:image/png;base64,' + returnedImages[imageIndex];
|
||||
img.src = "data:image/png;base64," + returnedImages[imageIndex];
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
|
@ -385,6 +384,25 @@ function snap(i, scaled = true) {
|
|||
return -snapOffset;
|
||||
}
|
||||
|
||||
function march() {
|
||||
if (marching) {
|
||||
marchOffset++;
|
||||
if (marchOffset > 16) {
|
||||
marchOffset = 0;
|
||||
}
|
||||
drawMarchingAnts();
|
||||
setTimeout(march, 20);
|
||||
}
|
||||
}
|
||||
|
||||
function drawMarchingAnts() {
|
||||
clearTargetMask();
|
||||
tgtCtx.strokeStyle = "#333333FF"; //"#55000077";
|
||||
tgtCtx.setLineDash([4, 2]);
|
||||
tgtCtx.lineDashOffset = -marchOffset;
|
||||
tgtCtx.strokeRect(marchCoords.x, marchCoords.y, marchCoords.w, marchCoords.h);
|
||||
}
|
||||
|
||||
function mouseMove(evt) {
|
||||
const rect = ovCanvas.getBoundingClientRect(); // not-quite pixel offset was driving me insane
|
||||
const canvasOffsetX = rect.left;
|
||||
|
@ -411,7 +429,7 @@ function mouseMove(evt) {
|
|||
ovCtx.drawImage(arbitraryImage, finalX, finalY);
|
||||
} else if (!paintMode) {
|
||||
// draw targeting square reticle thingy cursor
|
||||
ovCtx.strokeStyle = '#00000077';
|
||||
ovCtx.strokeStyle = "#00000077";
|
||||
snapOffsetX = 0;
|
||||
snapOffsetY = 0;
|
||||
if (snapToGrid) {
|
||||
|
@ -433,39 +451,39 @@ function mouseMove(evt) {
|
|||
* Mask implementation
|
||||
*/
|
||||
mouse.listen.canvas.onmousemove.on((evn) => {
|
||||
if (paintMode && evn.target.id === 'overlayCanvas') {
|
||||
if (paintMode && evn.target.id === "overlayCanvas") {
|
||||
// draw big translucent red blob cursor
|
||||
ovCtx.beginPath();
|
||||
ovCtx.arc(evn.x, evn.y, 4 * scaleFactor, 0, 2 * Math.PI, true); // for some reason 4x on an arc is === to 8x on a line???
|
||||
ovCtx.fillStyle = '#FF6A6A50';
|
||||
ovCtx.fillStyle = "#FF6A6A50";
|
||||
ovCtx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
mouse.listen.canvas.left.onpaint.on((evn) => {
|
||||
if (paintMode && evn.target.id === 'overlayCanvas') {
|
||||
maskPaintCtx.globalCompositeOperation = 'source-over';
|
||||
maskPaintCtx.strokeStyle = '#FF6A6A';
|
||||
if (paintMode && evn.target.id === "overlayCanvas") {
|
||||
maskPaintCtx.globalCompositeOperation = "source-over";
|
||||
maskPaintCtx.strokeStyle = "#FF6A6A";
|
||||
|
||||
maskPaintCtx.lineWidth = 8 * scaleFactor;
|
||||
maskPaintCtx.beginPath();
|
||||
maskPaintCtx.moveTo(evn.px, evn.py);
|
||||
maskPaintCtx.lineTo(evn.x, evn.y);
|
||||
maskPaintCtx.lineJoin = maskPaintCtx.lineCap = 'round';
|
||||
maskPaintCtx.lineJoin = maskPaintCtx.lineCap = "round";
|
||||
maskPaintCtx.stroke();
|
||||
}
|
||||
});
|
||||
|
||||
mouse.listen.canvas.right.onpaint.on((evn) => {
|
||||
if (paintMode && evn.target.id === 'overlayCanvas') {
|
||||
maskPaintCtx.globalCompositeOperation = 'destination-out';
|
||||
maskPaintCtx.strokeStyle = '#FFFFFFFF';
|
||||
if (paintMode && evn.target.id === "overlayCanvas") {
|
||||
maskPaintCtx.globalCompositeOperation = "destination-out";
|
||||
maskPaintCtx.strokeStyle = "#FFFFFFFF";
|
||||
|
||||
maskPaintCtx.lineWidth = 8 * scaleFactor;
|
||||
maskPaintCtx.beginPath();
|
||||
maskPaintCtx.moveTo(evn.px, evn.py);
|
||||
maskPaintCtx.lineTo(evn.x, evn.y);
|
||||
maskPaintCtx.lineJoin = maskPaintCtx.lineCap = 'round';
|
||||
maskPaintCtx.lineJoin = maskPaintCtx.lineCap = "round";
|
||||
maskPaintCtx.stroke();
|
||||
}
|
||||
});
|
||||
|
@ -494,10 +512,7 @@ function mouseDown(evt) {
|
|||
rect.left +
|
||||
oddOffset; //origin is middle of the frame
|
||||
nextBox.y =
|
||||
evt.clientY -
|
||||
(basePixelCount * scaleFactor) / 2 -
|
||||
rect.top +
|
||||
oddOffset; //TODO make a way to set the origin to numpad dirs?
|
||||
evt.clientY - (basePixelCount * scaleFactor) / 2 - rect.top + oddOffset; //TODO make a way to set the origin to numpad dirs?
|
||||
nextBox.w = basePixelCount * scaleFactor;
|
||||
nextBox.h = basePixelCount * scaleFactor;
|
||||
drawTargets.push(nextBox);
|
||||
|
@ -505,15 +520,11 @@ function mouseDown(evt) {
|
|||
} 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');
|
||||
ctx = imgCanvas.getContext("2d");
|
||||
if (snapToGrid) {
|
||||
ctx.clearRect(
|
||||
canvasX +
|
||||
snap(canvasX) -
|
||||
(basePixelCount * scaleFactor) / 2,
|
||||
canvasY +
|
||||
snap(canvasY) -
|
||||
(basePixelCount * scaleFactor) / 2,
|
||||
canvasX + snap(canvasX) - (basePixelCount * scaleFactor) / 2,
|
||||
canvasY + snap(canvasY) - (basePixelCount * scaleFactor) / 2,
|
||||
basePixelCount * scaleFactor,
|
||||
basePixelCount * scaleFactor
|
||||
);
|
||||
|
@ -557,8 +568,7 @@ function mouseUp(evt) {
|
|||
if (!blockNewImages) {
|
||||
//TODO seriously, refactor this
|
||||
blockNewImages = true;
|
||||
clearTargetMask();
|
||||
tgtCtx.strokeStyle = '#55000077';
|
||||
marching = true;
|
||||
var drawIt = {}; //why am i doing this????
|
||||
var target = drawTargets[drawTargets.length - 1]; //get the last one... why am i storing all of them?
|
||||
var oddOffset = 0;
|
||||
|
@ -574,27 +584,19 @@ function mouseUp(evt) {
|
|||
finalX = snapOffsetX + target.x - oddOffset;
|
||||
finalY = snapOffsetY + target.y - oddOffset;
|
||||
|
||||
drawThis.x = finalX;
|
||||
drawThis.y = finalY;
|
||||
drawThis.w = target.w;
|
||||
drawThis.h = target.h;
|
||||
tgtCtx.strokeRect(finalX, finalY, target.w, target.h);
|
||||
drawThis.x = marchCoords.x = finalX;
|
||||
drawThis.y = marchCoords.y = finalY;
|
||||
drawThis.w = marchCoords.w = target.w;
|
||||
drawThis.h = marchCoords.h = target.h;
|
||||
march(finalX, finalY, target.w, target.h);
|
||||
drawIt = drawThis; //TODO this is WRONG but also explicitly only draws the last image ... i think
|
||||
//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
|
||||
)
|
||||
) {
|
||||
if (!isCanvasBlank(drawIt.x, drawIt.y, drawIt.w, drawIt.h, imgCanvas)) {
|
||||
// image exists, set up for img2img
|
||||
var mainCanvasCtx = document
|
||||
.getElementById('canvas')
|
||||
.getContext('2d');
|
||||
.getElementById("canvas")
|
||||
.getContext("2d");
|
||||
const imgChunk = mainCanvasCtx.getImageData(
|
||||
drawIt.x,
|
||||
drawIt.y,
|
||||
|
@ -603,22 +605,15 @@ function mouseUp(evt) {
|
|||
); // 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 initImgCanvas = document.getElementById(
|
||||
'initImgCanvasMonitor'
|
||||
);
|
||||
var overMaskCanvas = document.getElementById(
|
||||
'overMaskCanvasMonitor'
|
||||
);
|
||||
var initImgCanvas = document.getElementById("initImgCanvasMonitor");
|
||||
var overMaskCanvas = document.getElementById("overMaskCanvasMonitor");
|
||||
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');
|
||||
var initImgCanvasCtx = initImgCanvas.getContext("2d");
|
||||
var overMaskCanvasCtx = overMaskCanvas.getContext("2d");
|
||||
// get blank pixels to use as mask
|
||||
const initImgData = mainCanvasCtx.createImageData(
|
||||
drawIt.w,
|
||||
drawIt.h
|
||||
);
|
||||
const overMaskImgData = overMaskCanvasCtx.createImageData(
|
||||
const initImgData = mainCanvasCtx.createImageData(drawIt.w, drawIt.h);
|
||||
let overMaskImgData = overMaskCanvasCtx.createImageData(
|
||||
drawIt.w,
|
||||
drawIt.h
|
||||
);
|
||||
|
@ -651,182 +646,36 @@ function mouseUp(evt) {
|
|||
initImgData.data[i + 3] = imgChunkData[i + 3]; //it's still RGBA so we can handily do this in nice chunks'o'4
|
||||
}
|
||||
}
|
||||
// make a list of all the white pixels to expand so we don't waste time on non-mask pixels
|
||||
let pix = { x: [], y: [], index: [] };
|
||||
var x, y, index;
|
||||
for (y = 0; y < drawIt.h; y++) {
|
||||
for (x = 0; x < drawIt.w; x++) {
|
||||
index = (y * drawIt.w + x) * 4;
|
||||
if (overMaskImgData.data[index] > 0) {
|
||||
pix.x.push(x);
|
||||
pix.y.push(y);
|
||||
pix.index.push(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < pix.index.length; i++) {
|
||||
// get the index in the stupid array
|
||||
// why? it's unused
|
||||
// var currentMaskPixelIndex = pix.index[i];
|
||||
|
||||
// for any horizontal expansion, we need to ensure that the target pixel is in the same Y row
|
||||
// horizontal left (west) is index-4 per pixel
|
||||
// horizontal right (east) is index+4 per pixel
|
||||
var currentMaskPixelY = pix.y[i];
|
||||
|
||||
// for any vertical expansion, we need to ensure that the target pixel is in the same X column
|
||||
// vertical up (north) is index-(imagedata.width) per pixel
|
||||
// vertical down (south) is index+(imagedata.width) per pixel
|
||||
var currentMaskPixelX = pix.x[i];
|
||||
|
||||
// i hate uint8clampedarray and math
|
||||
// primarily math
|
||||
// actually just my brain
|
||||
// ok so now lets check neighbors to see if they're in the same row/column
|
||||
for (j = overMaskPx; j > 0; j--) {
|
||||
// set a variable to the extreme end of the overmask size and work our way back inwards
|
||||
// i hate uint8clampedarray and math
|
||||
// this is so inefficient but i warned you all i'm bad at this
|
||||
//TODO refactor like all of this, it's horrible and shameful
|
||||
// BUT IT WORKS
|
||||
// but it is crushingly inefficient i'm sure
|
||||
// BUT IT WORKS and i came up with it all by myself because i'm a big boy
|
||||
|
||||
// ... sigh it doesn't work _well_
|
||||
// just moves the seam
|
||||
//TODO find a way to fade/gradient the edge without making weird artifacts or literally crashing the browser with inefficient data storage
|
||||
|
||||
// west
|
||||
var potentialPixelIndex =
|
||||
(currentMaskPixelY * drawIt.w +
|
||||
currentMaskPixelX) *
|
||||
4 -
|
||||
j * 4;
|
||||
var potentialPixelX =
|
||||
(potentialPixelIndex / 4) % drawIt.w;
|
||||
var potentialPixelY = Math.floor(
|
||||
potentialPixelIndex / 4 / drawIt.w
|
||||
if (overMaskPx > 0) {
|
||||
// https://stackoverflow.com/a/30204783 ???? !!!!!!!!
|
||||
overMaskCanvasCtx.fillStyle = "black";
|
||||
overMaskCanvasCtx.fillRect(0, 0, drawIt.w, drawIt.h); // fill with black instead of null to start
|
||||
for (i = 0; i < overMaskImgData.data.length; i += 4) {
|
||||
if (overMaskImgData.data[i] == 255) {
|
||||
// white pixel?
|
||||
// just blotch all over the thing
|
||||
var rando = Math.floor(Math.random() * overMaskPx);
|
||||
overMaskCanvasCtx.beginPath();
|
||||
overMaskCanvasCtx.arc(
|
||||
(i / 4) % overMaskCanvas.width,
|
||||
Math.floor(i / 4 / overMaskCanvas.width),
|
||||
scaleFactor + rando, // was 4 * sf + rando, too big
|
||||
0,
|
||||
2 * Math.PI,
|
||||
true
|
||||
);
|
||||
// west/east: ENSURE SAME ROW using the y axis unintuitively
|
||||
if (potentialPixelY == currentMaskPixelY) {
|
||||
// ok then
|
||||
// ensure it's not already a mask pixel
|
||||
if (
|
||||
overMaskImgData.data[potentialPixelIndex] !=
|
||||
255
|
||||
) {
|
||||
// welp fingers crossed
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 1
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 2
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 3
|
||||
] = 255;
|
||||
overMaskCanvasCtx.fillStyle = "#FFFFFFFF";
|
||||
overMaskCanvasCtx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
// east
|
||||
var potentialPixelIndex =
|
||||
(currentMaskPixelY * drawIt.w +
|
||||
currentMaskPixelX) *
|
||||
4 +
|
||||
j * 4;
|
||||
var potentialPixelX =
|
||||
(potentialPixelIndex / 4) % drawIt.w;
|
||||
var potentialPixelY = Math.floor(
|
||||
potentialPixelIndex / 4 / drawIt.w
|
||||
overMaskImgData = overMaskCanvasCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
overMaskCanvas.width,
|
||||
overMaskCanvas.height
|
||||
);
|
||||
if (potentialPixelY == currentMaskPixelY) {
|
||||
if (
|
||||
overMaskImgData.data[potentialPixelIndex] !=
|
||||
255
|
||||
) {
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 1
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 2
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 3
|
||||
] = 255;
|
||||
overMaskCanvasCtx.putImageData(overMaskImgData, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// north
|
||||
var potentialPixelIndex =
|
||||
(currentMaskPixelY * drawIt.w +
|
||||
currentMaskPixelX) *
|
||||
4 -
|
||||
j * drawIt.w * 4;
|
||||
var potentialPixelX =
|
||||
(potentialPixelIndex / 4) % drawIt.w;
|
||||
var potentialPixelY = Math.floor(
|
||||
potentialPixelIndex / 4 / drawIt.w
|
||||
);
|
||||
// north/south: ENSURE SAME COLUMN using the x axis unintuitively
|
||||
if (potentialPixelX == currentMaskPixelX) {
|
||||
if (
|
||||
overMaskImgData.data[potentialPixelIndex] !=
|
||||
255
|
||||
) {
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 1
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 2
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 3
|
||||
] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// south
|
||||
var potentialPixelIndex =
|
||||
(currentMaskPixelY * drawIt.w +
|
||||
currentMaskPixelX) *
|
||||
4 +
|
||||
j * drawIt.w * 4;
|
||||
var potentialPixelX =
|
||||
(potentialPixelIndex / 4) % drawIt.w;
|
||||
var potentialPixelY = Math.floor(
|
||||
potentialPixelIndex / 4 / drawIt.w
|
||||
);
|
||||
if (potentialPixelX == currentMaskPixelX) {
|
||||
if (
|
||||
overMaskImgData.data[potentialPixelIndex] !=
|
||||
255
|
||||
) {
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 1
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 2
|
||||
] = 255;
|
||||
overMaskImgData.data[
|
||||
potentialPixelIndex + 3
|
||||
] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// also check for painted masks in region, add them as white pixels to mask canvas
|
||||
const maskChunk = maskPaintCtx.getImageData(
|
||||
drawIt.x,
|
||||
|
@ -844,10 +693,7 @@ function mouseUp(evt) {
|
|||
}
|
||||
}
|
||||
// backup any painted masks ingested then them, replacable if user doesn't like resultant image
|
||||
var clearArea = maskPaintCtx.createImageData(
|
||||
drawIt.w,
|
||||
drawIt.h
|
||||
);
|
||||
var clearArea = maskPaintCtx.createImageData(drawIt.w, drawIt.h);
|
||||
backupMaskChunk = maskChunk;
|
||||
backupMaskX = drawIt.x;
|
||||
backupMaskY = drawIt.y;
|
||||
|
@ -863,19 +709,18 @@ function mouseUp(evt) {
|
|||
initImgCanvasCtx.putImageData(initImgData, 0, 0);
|
||||
var initImgBase64 = initImgCanvas.toDataURL();
|
||||
// anyway all that to say NOW let's run img2img
|
||||
endpoint = 'img2img';
|
||||
endpoint = "img2img";
|
||||
stableDiffusionData.mask = overMaskBase64;
|
||||
stableDiffusionData.init_images = [initImgBase64];
|
||||
// slightly more involved than txt2img
|
||||
} else {
|
||||
// time to run txt2img
|
||||
endpoint = 'txt2img';
|
||||
endpoint = "txt2img";
|
||||
// easy enough
|
||||
}
|
||||
stableDiffusionData.prompt =
|
||||
document.getElementById('prompt').value;
|
||||
stableDiffusionData.prompt = document.getElementById("prompt").value;
|
||||
stableDiffusionData.negative_prompt =
|
||||
document.getElementById('negPrompt').value;
|
||||
document.getElementById("negPrompt").value;
|
||||
stableDiffusionData.width = drawIt.w;
|
||||
stableDiffusionData.height = drawIt.h;
|
||||
stableDiffusionData.firstphase_height = drawIt.h / 2;
|
||||
|
@ -886,95 +731,94 @@ function mouseUp(evt) {
|
|||
}
|
||||
}
|
||||
|
||||
const changeScaleFactor = sliderChangeHandlerFactory(
|
||||
'scaleFactor',
|
||||
'scaleFactorTxt',
|
||||
'scaleFactor',
|
||||
8,
|
||||
(k, v) => (scaleFactor = v),
|
||||
(k) => scaleFactor
|
||||
);
|
||||
const changeSteps = sliderChangeHandlerFactory(
|
||||
'steps',
|
||||
'stepsTxt',
|
||||
'steps',
|
||||
30
|
||||
);
|
||||
|
||||
function changePaintMode() {
|
||||
paintMode = document.getElementById('cbxPaint').checked;
|
||||
paintMode = document.getElementById("cbxPaint").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);
|
||||
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);
|
||||
document.getElementById("samplerSelect").value;
|
||||
localStorage.setItem("sampler", stableDiffusionData.sampler_index);
|
||||
}
|
||||
|
||||
const changeCfgScale = sliderChangeHandlerFactory(
|
||||
'cfgScale',
|
||||
'cfgScaleTxt',
|
||||
'cfg_scale',
|
||||
"cfgScale",
|
||||
"cfgScaleTxt",
|
||||
"cfg_scale",
|
||||
7.0
|
||||
);
|
||||
const changeBatchSize = sliderChangeHandlerFactory(
|
||||
'batchSize',
|
||||
'batchSizeText',
|
||||
'batch_size',
|
||||
"batchSize",
|
||||
"batchSizeText",
|
||||
"batch_size",
|
||||
2
|
||||
);
|
||||
const changeBatchCount = sliderChangeHandlerFactory(
|
||||
'batchCount',
|
||||
'batchCountText',
|
||||
'n_iter',
|
||||
"batchCount",
|
||||
"batchCountText",
|
||||
"n_iter",
|
||||
2
|
||||
);
|
||||
const changeScaleFactor = sliderChangeHandlerFactory(
|
||||
"scaleFactor",
|
||||
"scaleFactorTxt",
|
||||
"scaleFactor",
|
||||
8,
|
||||
(k, v) => (scaleFactor = v),
|
||||
(k) => scaleFactor
|
||||
);
|
||||
const changeSteps = sliderChangeHandlerFactory(
|
||||
"steps",
|
||||
"stepsTxt",
|
||||
"steps",
|
||||
30
|
||||
);
|
||||
|
||||
function changeSnapMode() {
|
||||
snapToGrid = document.getElementById('cbxSnap').checked;
|
||||
snapToGrid = document.getElementById("cbxSnap").checked;
|
||||
}
|
||||
|
||||
function changeMaskBlur() {
|
||||
stableDiffusionData.mask_blur = document.getElementById('maskBlur').value;
|
||||
localStorage.setItem('mask_blur', stableDiffusionData.mask_blur);
|
||||
stableDiffusionData.mask_blur = document.getElementById("maskBlur").value;
|
||||
localStorage.setItem("mask_blur", stableDiffusionData.mask_blur);
|
||||
}
|
||||
|
||||
function changeSeed() {
|
||||
stableDiffusionData.seed = document.getElementById('seed').value;
|
||||
localStorage.setItem('seed', stableDiffusionData.seed);
|
||||
stableDiffusionData.seed = document.getElementById("seed").value;
|
||||
localStorage.setItem("seed", stableDiffusionData.seed);
|
||||
}
|
||||
|
||||
function changeOverMaskPx() {
|
||||
overMaskPx = document.getElementById('overMaskPx').value;
|
||||
localStorage.setItem('overmask_px', overMaskPx);
|
||||
overMaskPx = document.getElementById("overMaskPx").value;
|
||||
localStorage.setItem("overmask_px", overMaskPx);
|
||||
}
|
||||
|
||||
function changeHiResFix() {
|
||||
stableDiffusionData.enable_hr = Boolean(
|
||||
document.getElementById('cbxHRFix').checked
|
||||
document.getElementById("cbxHRFix").checked
|
||||
);
|
||||
localStorage.setItem('enable_hr', stableDiffusionData.enable_hr);
|
||||
localStorage.setItem("enable_hr", stableDiffusionData.enable_hr);
|
||||
}
|
||||
|
||||
function isCanvasBlank(x, y, w, h, specifiedCanvas) {
|
||||
var canvas = document.getElementById(specifiedCanvas.id);
|
||||
return !canvas
|
||||
.getContext('2d')
|
||||
.getContext("2d")
|
||||
.getImageData(x, y, w, h)
|
||||
.data.some((channel) => channel !== 0);
|
||||
}
|
||||
|
||||
function drawBackground() {
|
||||
bgCtx.lineWidth = 1;
|
||||
bgCtx.strokeStyle = '#999';
|
||||
bgCtx.strokeStyle = "#999";
|
||||
var gridbox = bgCanvas.getBoundingClientRect();
|
||||
for (var i = 0; i < gridbox.width; i += 64) {
|
||||
bgCtx.moveTo(i, 0);
|
||||
|
@ -989,16 +833,17 @@ function drawBackground() {
|
|||
}
|
||||
|
||||
function preloadImage() {
|
||||
// gonna legit scream
|
||||
document.getElementById('overlayCanvas').onmousemove = null;
|
||||
document.getElementById('overlayCanvas').onmousedown = null;
|
||||
document.getElementById('overlayCanvas').onmouseup = null;
|
||||
// possible firefox-only bug?
|
||||
// attempt to prevent requesting a dream if double-clicking a selected image
|
||||
document.getElementById("overlayCanvas").onmousemove = null;
|
||||
document.getElementById("overlayCanvas").onmousedown = null;
|
||||
document.getElementById("overlayCanvas").onmouseup = null;
|
||||
|
||||
var file = document.getElementById('preloadImage').files[0];
|
||||
var file = document.getElementById("preloadImage").files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (evt) {
|
||||
var imgCanvas = document.createElement('canvas');
|
||||
var imgCtx = imgCanvas.getContext('2d');
|
||||
var imgCanvas = document.createElement("canvas");
|
||||
var imgCtx = imgCanvas.getContext("2d");
|
||||
arbitraryImage = new Image();
|
||||
arbitraryImage.onload = function () {
|
||||
blockNewImages = true;
|
||||
|
@ -1015,9 +860,9 @@ function preloadImage() {
|
|||
arbitraryImageBitmap = createImageBitmap(arbitraryImageData); // apparently that either... maybe just the raw image?
|
||||
arbitraryImageBase64 = imgCanvas.toDataURL();
|
||||
placingArbitraryImage = true;
|
||||
document.getElementById('overlayCanvas').onmousemove = mouseMove;
|
||||
document.getElementById('overlayCanvas').onmousedown = mouseDown;
|
||||
document.getElementById('overlayCanvas').onmouseup = mouseUp;
|
||||
document.getElementById("overlayCanvas").onmousemove = mouseMove;
|
||||
document.getElementById("overlayCanvas").onmousedown = mouseDown;
|
||||
document.getElementById("overlayCanvas").onmouseup = mouseUp;
|
||||
};
|
||||
arbitraryImage.src = evt.target.result;
|
||||
};
|
||||
|
@ -1025,16 +870,13 @@ function preloadImage() {
|
|||
}
|
||||
|
||||
function downloadCanvas() {
|
||||
var link = document.createElement('a');
|
||||
var link = document.createElement("a");
|
||||
link.download =
|
||||
new Date()
|
||||
.toISOString()
|
||||
.slice(0, 19)
|
||||
.replace('T', ' ')
|
||||
.replace(':', ' ') + ' openOutpaint image.png';
|
||||
new Date().toISOString().slice(0, 19).replace("T", " ").replace(":", " ") +
|
||||
" openOutpaint image.png";
|
||||
var croppedCanvas = cropCanvas(imgCanvas);
|
||||
if (croppedCanvas != null) {
|
||||
link.href = croppedCanvas.toDataURL('image/png');
|
||||
link.href = croppedCanvas.toDataURL("image/png");
|
||||
link.click();
|
||||
}
|
||||
}
|
||||
|
@ -1043,7 +885,7 @@ function cropCanvas(sourceCanvas) {
|
|||
var w = sourceCanvas.width;
|
||||
var h = sourceCanvas.height;
|
||||
var pix = {x: [], y: []};
|
||||
var imageData = sourceCanvas.getContext('2d').getImageData(0, 0, w, h);
|
||||
var imageData = sourceCanvas.getContext("2d").getImageData(0, 0, w, h);
|
||||
var x, y, index;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
|
@ -1072,12 +914,12 @@ function cropCanvas(sourceCanvas) {
|
|||
|
||||
try {
|
||||
var cut = sourceCanvas
|
||||
.getContext('2d')
|
||||
.getContext("2d")
|
||||
.getImageData(pix.x[0], pix.y[0], w, h);
|
||||
var cutCanvas = document.createElement('canvas');
|
||||
var cutCanvas = document.createElement("canvas");
|
||||
cutCanvas.width = w;
|
||||
cutCanvas.height = h;
|
||||
cutCanvas.getContext('2d').putImageData(cut, 0, 0);
|
||||
cutCanvas.getContext("2d").putImageData(cut, 0, 0);
|
||||
} catch (ex) {
|
||||
// probably empty image
|
||||
//TODO confirm edge cases?
|
||||
|
@ -1087,16 +929,16 @@ function cropCanvas(sourceCanvas) {
|
|||
}
|
||||
|
||||
function checkIfWebuiIsRunning() {
|
||||
var url = document.getElementById('host').value + '/startup-events';
|
||||
var url = document.getElementById("host").value + "/startup-events";
|
||||
fetch(url)
|
||||
.then((response) => {
|
||||
if (response.status == 200) {
|
||||
console.log('webui is running');
|
||||
console.log("webui is running");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(
|
||||
'WebUI doesnt seem to be running, please start it and try again\nCheck console for additional info\n' +
|
||||
"WebUI doesnt seem to be running, please start it and try again\nCheck console for additional info\n" +
|
||||
error
|
||||
);
|
||||
});
|
||||
|
@ -1105,38 +947,35 @@ function checkIfWebuiIsRunning() {
|
|||
function loadSettings() {
|
||||
// set default values if not set
|
||||
var _sampler =
|
||||
localStorage.getItem('sampler') == null
|
||||
? 'DDIM'
|
||||
: localStorage.getItem('sampler');
|
||||
localStorage.getItem("sampler") == null
|
||||
? "DDIM"
|
||||
: localStorage.getItem("sampler");
|
||||
var _mask_blur =
|
||||
localStorage.getItem('mask_blur') == null
|
||||
localStorage.getItem("mask_blur") == null
|
||||
? 0
|
||||
: localStorage.getItem('mask_blur');
|
||||
: localStorage.getItem("mask_blur");
|
||||
var _seed =
|
||||
localStorage.getItem('seed') == null
|
||||
? -1
|
||||
: localStorage.getItem('seed');
|
||||
localStorage.getItem("seed") == null ? -1 : localStorage.getItem("seed");
|
||||
var _enable_hr = Boolean(
|
||||
localStorage.getItem('enable_hr') == (null || 'false')
|
||||
localStorage.getItem("enable_hr") == (null || "false")
|
||||
? false
|
||||
: localStorage.getItem('enable_hr')
|
||||
: localStorage.getItem("enable_hr")
|
||||
);
|
||||
var _enable_erase = Boolean(
|
||||
localStorage.getItem('enable_erase') == (null || 'false')
|
||||
localStorage.getItem("enable_erase") == (null || "false")
|
||||
? false
|
||||
: localStorage.getItem('enable_erase')
|
||||
: localStorage.getItem("enable_erase")
|
||||
);
|
||||
var _overmask_px =
|
||||
localStorage.getItem('overmask_px') == null
|
||||
localStorage.getItem("overmask_px") == null
|
||||
? 0
|
||||
: localStorage.getItem('overmask_px');
|
||||
: localStorage.getItem("overmask_px");
|
||||
|
||||
// set the values into the UI
|
||||
document.getElementById('samplerSelect').value = String(_sampler);
|
||||
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);
|
||||
document.getElementById('overMaskPx').value = Number(_overmask_px);
|
||||
document.getElementById("samplerSelect").value = String(_sampler);
|
||||
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);
|
||||
document.getElementById("overMaskPx").value = Number(_overmask_px);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ function dragElement(elmnt) {
|
|||
p2 = 0,
|
||||
p3 = 0,
|
||||
p4 = 0;
|
||||
var draggableElements = document.getElementsByClassName('draggable');
|
||||
var draggableElements = document.getElementsByClassName("draggable");
|
||||
for (var i = 0; i < draggableElements.length; i++) {
|
||||
draggableElements[i].onmousedown = dragMouseDown;
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ function dragElement(elmnt) {
|
|||
e.preventDefault();
|
||||
p1 = p3 - e.clientX;
|
||||
p2 = p4 - e.clientY;
|
||||
elmnt.style.top = (elmnt.offsetTop - (p4-e.clientY)) + "px";
|
||||
elmnt.style.left = (elmnt.offsetLeft - (p3-e.clientX)) + "px";
|
||||
elmnt.style.top = elmnt.offsetTop - (p4 - e.clientY) + "px";
|
||||
elmnt.style.left = elmnt.offsetLeft - (p3 - e.clientX) + "px";
|
||||
p3 = e.clientX;
|
||||
p4 = e.clientY;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue