Merge pull request #110 from zero01101/testing

WebUI Extension Fixes
This commit is contained in:
Victor Seiji Hariki 2022-12-19 17:49:53 -03:00 committed by GitHub
commit 366507604a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 269 additions and 52 deletions

3
.gitignore vendored
View file

@ -1,5 +1,8 @@
.vscode/* .vscode/*
# Key for embedding
key.json
# NPM things # NPM things
package.json package.json
package-lock.json package-lock.json

View file

@ -299,7 +299,7 @@
<button id="settings-btn-close" class="close"></button> <button id="settings-btn-close" class="close"></button>
</div> </div>
<div class="ui separator"></div> <div class="ui separator"></div>
<iframe id="page-overlay" src="/pages/configuration.html"></iframe> <iframe id="page-overlay" src="pages/configuration.html"></iframe>
</div> </div>
</div> </div>
@ -345,5 +345,8 @@
src="js/initalize/debug.populate.js" src="js/initalize/debug.populate.js"
type="text/javascript"></script> type="text/javascript"></script>
<script src="js/initalize/ui.populate.js" type="text/javascript"></script> <script src="js/initalize/ui.populate.js" type="text/javascript"></script>
<!-- Deals with webui communication -->
<script src="js/webui.js" type="text/javascript"></script>
</body> </body>
</html> </html>

View file

@ -1,6 +1,86 @@
//TODO FIND OUT WHY I HAVE TO RESIZE A TEXTBOX AND THEN START USING IT TO AVOID THE 1px WHITE LINE ON LEFT EDGES DURING IMG2IMG //TODO FIND OUT WHY I HAVE TO RESIZE A TEXTBOX AND THEN START USING IT TO AVOID THE 1px WHITE LINE ON LEFT EDGES DURING IMG2IMG
//...lmao did setting min width 200 on info div fix that accidentally? once the canvas is infinite and the menu bar is hideable it'll probably be a problem again //...lmao did setting min width 200 on info div fix that accidentally? once the canvas is infinite and the menu bar is hideable it'll probably be a problem again
/**
* Workaround for Firefox bug #733698
*
* https://bugzilla.mozilla.org/show_bug.cgi?id=733698
*
* Workaround by https://github.com/subzey on https://gist.github.com/subzey/2030480
*
* Replaces and handles NS_ERROR_FAILURE errors triggered by 733698.
*/
(function () {
var FakeTextMetrics,
proto,
fontSetterNative,
measureTextNative,
fillTextNative,
strokeTextNative;
if (
!window.CanvasRenderingContext2D ||
!window.TextMetrics ||
!(proto = window.CanvasRenderingContext2D.prototype) ||
!proto.hasOwnProperty("font") ||
!proto.hasOwnProperty("mozTextStyle") ||
typeof proto.__lookupSetter__ !== "function" ||
!(fontSetterNative = proto.__lookupSetter__("font"))
) {
return;
}
proto.__defineSetter__("font", function (value) {
try {
return fontSetterNative.call(this, value);
} catch (e) {
if (e.name !== "NS_ERROR_FAILURE") {
throw e;
}
}
});
measureTextNative = proto.measureText;
FakeTextMetrics = function () {
this.width = 0;
this.isFake = true;
this.__proto__ = window.TextMetrics.prototype;
};
proto.measureText = function ($0) {
try {
return measureTextNative.apply(this, arguments);
} catch (e) {
if (e.name !== "NS_ERROR_FAILURE") {
throw e;
} else {
return new FakeTextMetrics();
}
}
};
fillTextNative = proto.fillText;
proto.fillText = function ($0, $1, $2, $3) {
try {
fillTextNative.apply(this, arguments);
} catch (e) {
if (e.name !== "NS_ERROR_FAILURE") {
throw e;
}
}
};
strokeTextNative = proto.strokeText;
proto.strokeText = function ($0, $1, $2, $3) {
try {
strokeTextNative.apply(this, arguments);
} catch (e) {
if (e.name !== "NS_ERROR_FAILURE") {
throw e;
}
}
};
})();
window.onload = startup; window.onload = startup;
var stableDiffusionData = { var stableDiffusionData = {
@ -91,7 +171,7 @@ function startup() {
? hostEl.value.substring(0, hostEl.value.length - 1) ? hostEl.value.substring(0, hostEl.value.length - 1)
: hostEl.value; : hostEl.value;
hostEl.value = host; hostEl.value = host;
localStorage.setItem("host", host); localStorage.setItem("openoutpaint/host", host);
checkConnection(); checkConnection();
}; };
}); });
@ -112,7 +192,7 @@ function testHostConfiguration() {
* Check host configuration * Check host configuration
*/ */
const hostEl = document.getElementById("host"); const hostEl = document.getElementById("host");
hostEl.value = localStorage.getItem("host"); hostEl.value = localStorage.getItem("openoutpaint/host");
const requestHost = (prompt, def = "http://127.0.0.1:7860") => { const requestHost = (prompt, def = "http://127.0.0.1:7860") => {
let value = window.prompt(prompt, def); let value = window.prompt(prompt, def);
@ -121,12 +201,12 @@ function testHostConfiguration() {
value = value.endsWith("/") ? value.substring(0, value.length - 1) : value; value = value.endsWith("/") ? value.substring(0, value.length - 1) : value;
host = value; host = value;
hostEl.value = host; hostEl.value = host;
localStorage.setItem("host", host); localStorage.setItem("openoutpaint/host", host);
testHostConfiguration(); testHostConfiguration();
}; };
const current = localStorage.getItem("host"); const current = localStorage.getItem("openoutpaint/host");
if (current) { if (current) {
if (!current.match(/^https?:\/\/[a-z0-9][a-z0-9.]+[a-z0-9](:[0-9]+)?$/i)) if (!current.match(/^https?:\/\/[a-z0-9][a-z0-9.]+[a-z0-9](:[0-9]+)?$/i))
requestHost( requestHost(
@ -507,19 +587,19 @@ function changeMaskBlur() {
stableDiffusionData.mask_blur = parseInt( stableDiffusionData.mask_blur = parseInt(
document.getElementById("maskBlur").value document.getElementById("maskBlur").value
); );
localStorage.setItem("mask_blur", stableDiffusionData.mask_blur); localStorage.setItem("openoutpaint/mask_blur", stableDiffusionData.mask_blur);
} }
function changeSeed() { function changeSeed() {
stableDiffusionData.seed = document.getElementById("seed").value; stableDiffusionData.seed = document.getElementById("seed").value;
localStorage.setItem("seed", stableDiffusionData.seed); localStorage.setItem("openoutpaint/seed", stableDiffusionData.seed);
} }
function changeHiResFix() { function changeHiResFix() {
stableDiffusionData.enable_hr = Boolean( stableDiffusionData.enable_hr = Boolean(
document.getElementById("cbxHRFix").checked document.getElementById("cbxHRFix").checked
); );
localStorage.setItem("enable_hr", stableDiffusionData.enable_hr); localStorage.setItem("openoutpaint/enable_hr", stableDiffusionData.enable_hr);
} }
function changeSyncCursorSize() { function changeSyncCursorSize() {
@ -800,7 +880,10 @@ function changeStyles() {
}); });
} }
localStorage.setItem("promptStyle", JSON.stringify(selectedString)); localStorage.setItem(
"openoutpaint/promptStyle",
JSON.stringify(selectedString)
);
// change the model // change the model
if (selectedString.length > 0) if (selectedString.length > 0)
@ -821,16 +904,16 @@ async function getSamplers() {
})); }));
// Initial sampler // Initial sampler
if (localStorage.getItem("sampler") != null) { if (localStorage.getItem("openoutpaint/sampler") != null) {
samplerAutoComplete.value = localStorage.getItem("sampler"); samplerAutoComplete.value = localStorage.getItem("openoutpaint/sampler");
} else { } else {
samplerAutoComplete.value = data[0].name; samplerAutoComplete.value = data[0].name;
localStorage.setItem("sampler", samplerAutoComplete.value); localStorage.setItem("openoutpaint/sampler", samplerAutoComplete.value);
} }
samplerAutoComplete.onchange.on(({value}) => { samplerAutoComplete.onchange.on(({value}) => {
stableDiffusionData.sampler_index = value; stableDiffusionData.sampler_index = value;
localStorage.setItem("sampler", value); localStorage.setItem("openoutpaint/sampler", value);
}); });
} catch (e) { } catch (e) {
console.warn("[index] Failed to fetch samplers"); console.warn("[index] Failed to fetch samplers");
@ -841,8 +924,8 @@ async function upscaleAndDownload() {
// Future improvements: some upscalers take a while to upscale, so we should show a loading bar or something, also a slider for the upscale amount // Future improvements: some upscalers take a while to upscale, so we should show a loading bar or something, also a slider for the upscale amount
// get cropped canvas, send it to upscaler, download result // get cropped canvas, send it to upscaler, download result
var upscale_factor = localStorage.getItem("upscale_x") var upscale_factor = localStorage.getItem("openoutpaint/upscale_x")
? localStorage.getItem("upscale_x") ? localStorage.getItem("openoutpaint/upscale_x")
: 2; : 2;
var upscaler = upscalerAutoComplete.value; var upscaler = upscalerAutoComplete.value;
var croppedCanvas = cropCanvas( var croppedCanvas = cropCanvas(
@ -896,21 +979,23 @@ async function upscaleAndDownload() {
function loadSettings() { function loadSettings() {
// set default values if not set // set default values if not set
var _mask_blur = var _mask_blur =
localStorage.getItem("mask_blur") == null localStorage.getItem("openoutpaint/mask_blur") == null
? 0 ? 0
: localStorage.getItem("mask_blur"); : localStorage.getItem("openoutpaint/mask_blur");
var _seed = var _seed =
localStorage.getItem("seed") == null ? -1 : localStorage.getItem("seed"); localStorage.getItem("openoutpaint/seed") == null
? -1
: localStorage.getItem("openoutpaint/seed");
let _enable_hr = let _enable_hr =
localStorage.getItem("enable_hr") === null localStorage.getItem("openoutpaint/enable_hr") === null
? false ? false
: localStorage.getItem("enable_hr") === "true"; : localStorage.getItem("openoutpaint/enable_hr") === "true";
let _sync_cursor_size = let _sync_cursor_size =
localStorage.getItem("sync_cursor_size") === null localStorage.getItem("openoutpaint/sync_cursor_size") === null
? true ? true
: localStorage.getItem("sync_cursor_size") === "true"; : localStorage.getItem("openoutpaint/sync_cursor_size") === "true";
// set the values into the UI // set the values into the UI
document.getElementById("maskBlur").value = Number(_mask_blur); document.getElementById("maskBlur").value = Number(_mask_blur);

View file

@ -3,10 +3,14 @@ const imageCollection = layers.registerCollection(
"image", "image",
{ {
w: parseInt( w: parseInt(
(localStorage && localStorage.getItem("settings.canvas-width")) || 2048 (localStorage &&
localStorage.getItem("openoutpaint/settings.canvas-width")) ||
2048
), ),
h: parseInt( h: parseInt(
(localStorage && localStorage.getItem("settings.canvas-height")) || 2048 (localStorage &&
localStorage.getItem("openoutpaint/settings.canvas-height")) ||
2048
), ),
}, },
{ {
@ -57,7 +61,7 @@ const uiCtx = uiCanvas.getContext("2d", {desynchronized: true});
* Here we setup canvas dynamic scaling * Here we setup canvas dynamic scaling
*/ */
(() => { (() => {
let expandSize = localStorage.getItem("expand-size") || 1024; let expandSize = localStorage.getItem("openoutpaint/expand-size") || 1024;
expandSize = parseInt(expandSize, 10); expandSize = parseInt(expandSize, 10);
const askSize = () => { const askSize = () => {
@ -66,7 +70,7 @@ const uiCtx = uiCanvas.getContext("2d", {desynchronized: true});
if (!by) return null; if (!by) return null;
else { else {
const len = parseInt(by, 10); const len = parseInt(by, 10);
localStorage.setItem("expand-size", len); localStorage.setItem("openoutpaint/expand-size", len);
expandSize = len; expandSize = len;
return len; return len;
} }

View file

@ -20,8 +20,8 @@ async function getStyles() {
/** @type {string[]} */ /** @type {string[]} */
let stored = null; let stored = null;
try { try {
stored = JSON.parse(localStorage.getItem("promptStyle")); stored = JSON.parse(localStorage.getItem("openoutpaint/promptStyle"));
// doesn't seem to throw a syntaxerror if the localstorage item simply doesn't exist? // doesn't seem to throw a syntaxerror if the localStorage item simply doesn't exist?
if (stored == null) stored = []; if (stored == null) stored = [];
} catch (e) { } catch (e) {
stored = []; stored = [];
@ -40,11 +40,14 @@ async function getStyles() {
selected = value; selected = value;
} }
stableDiffusionData.styles = selected; stableDiffusionData.styles = selected;
localStorage.setItem("promptStyle", JSON.stringify(selected)); localStorage.setItem(
"openoutpaint/promptStyle",
JSON.stringify(selected)
);
}); });
styleSelectElement.value = stored; styleSelectElement.value = stored;
localStorage.setItem("promptStyle", JSON.stringify(stored)); localStorage.setItem("openoutpaint/promptStyle", JSON.stringify(stored));
} catch (e) { } catch (e) {
console.warn("[index] Failed to fetch prompt styles"); console.warn("[index] Failed to fetch prompt styles");
console.warn(e); console.warn(e);
@ -66,18 +69,21 @@ async function getStyles() {
promptEl.oninput = () => { promptEl.oninput = () => {
stableDiffusionData.prompt = promptEl.value; stableDiffusionData.prompt = promptEl.value;
promptEl.title = promptEl.value; promptEl.title = promptEl.value;
localStorage.setItem("prompt", stableDiffusionData.prompt); localStorage.setItem("openoutpaint/prompt", stableDiffusionData.prompt);
}; };
negativePromptEl.oninput = () => { negativePromptEl.oninput = () => {
stableDiffusionData.negative_prompt = negativePromptEl.value; stableDiffusionData.negative_prompt = negativePromptEl.value;
negativePromptEl.title = negativePromptEl.value; negativePromptEl.title = negativePromptEl.value;
localStorage.setItem("neg_prompt", stableDiffusionData.negative_prompt); localStorage.setItem(
"openoutpaint/neg_prompt",
stableDiffusionData.negative_prompt
);
}; };
// Load from local storage if set // Load from local storage if set
const storedPrompt = localStorage.getItem("prompt"); const storedPrompt = localStorage.getItem("openoutpaint/prompt");
const storedNeg = localStorage.getItem("neg_prompt"); const storedNeg = localStorage.getItem("openoutpaint/neg_prompt");
const promptDefaultValue = const promptDefaultValue =
storedPrompt === null ? defaultPrompt : storedPrompt; storedPrompt === null ? defaultPrompt : storedPrompt;
const negativePromptDefaultValue = const negativePromptDefaultValue =
@ -137,7 +143,7 @@ async function getStyles() {
stableDiffusionData.prompt = prompt; stableDiffusionData.prompt = prompt;
promptEl.title = prompt; promptEl.title = prompt;
promptEl.value = prompt; promptEl.value = prompt;
localStorage.setItem("prompt", prompt); localStorage.setItem("openoutpaint/prompt", prompt);
}); });
promptBtn.textContent = (samePrompt ? "= " : "") + prompt; promptBtn.textContent = (samePrompt ? "= " : "") + prompt;
@ -147,7 +153,7 @@ async function getStyles() {
stableDiffusionData.negative_prompt = negative; stableDiffusionData.negative_prompt = negative;
negativePromptEl.title = negative; negativePromptEl.title = negative;
negativePromptEl.value = negative; negativePromptEl.value = negative;
localStorage.setItem("neg_prompt", negative); localStorage.setItem("openoutpaint/neg_prompt", negative);
}); });
negativeBtn.textContent = (sameNegativePrompt ? "= " : "") + negative; negativeBtn.textContent = (sameNegativePrompt ? "= " : "") + negative;

109
js/webui.js Normal file
View file

@ -0,0 +1,109 @@
/**
* This file should only be actually loaded if we are in a trusted environment.
*/
(async () => {
// Check if key file exists
const response = await fetch("key.json");
/** @type {{host?: string, trusted?: boolean, key: string}} */
let data = null;
if (response.status === 200) {
data = await response.json();
console.info("[webui] key.json loaded successfully");
}
if (response.status !== 200 || (!data.key && !data.trusted)) {
console.warn(
"[webui] An accessible key.json file with a 'key' or 'trusted' should be provided to allow for messaging"
);
console.warn(data);
return;
}
const key = data.key;
// Check if we are running inside an iframe or embed
try {
const frame = window.frameElement;
if (frame === null) {
console.info("[webui] Not running inside a frame");
} else {
console.info(
`[webui] Window is child of '${window.parent.document.URL}'`
);
if (data.host && !window.parent.document.URL.startsWith(data.host)) {
console.warn(
`[webui] Window does not trust parent '${window.parent.document.URL}'`
);
console.warn("[webui] Will NOT setup message listeners");
return;
}
}
} catch (e) {
console.warn(
`[webui] Running in a third party iframe or embed, and blocked by CORS`
);
console.warn(e);
return;
}
if (data) {
let parentWindow = null;
if (!data.trusted) console.debug(`[webui] Loaded key`);
window.addEventListener("message", ({data, origin, source}) => {
if (!data.trusted && data.key !== key) {
console.warn(
`[webui] Message with incorrect key was received from '${origin}'`
);
console.warn(data);
return;
}
if (!parentWindow && !data.type === "openoutpaint/init") {
console.warn(`[webui] Communication has not been initialized`);
}
try {
switch (data.type) {
case "openoutpaint/init":
parentWindow = source;
console.debug(
`[webui] Communication with '${origin}' has been initialized`
);
break;
case "openoutpaint/add-resource":
{
const image = document.createElement("img");
image.src = data.image.dataURL;
image.onload = async () => {
await tools.stamp.state.addResource(
data.image.resourceName || "External Resource",
image
);
tools.stamp.enable();
};
}
break;
default:
console.warn(`[webui] Unsupported message type: ${data.type}`);
break;
}
// Send acknowledgement
parentWindow &&
parentWindow.postMessage({
type: "openoutpaint/ack",
message: data,
});
} catch (e) {
console.warn(
`[webui] Message of type '${data.type}' has invalid format`
);
console.warn(e);
console.warn(data);
}
});
}
})();

View file

@ -4,22 +4,22 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>openOutpaint 🐠</title> <title>openOutpaint 🐠</title>
<!-- CSS Variables --> <!-- CSS Variables -->
<link href="/css/colors.css" rel="stylesheet" /> <link href="../css/colors.css" rel="stylesheet" />
<link href="/css/icons.css" rel="stylesheet" /> <link href="../css/icons.css" rel="stylesheet" />
<link href="/css/index.css" rel="stylesheet" /> <link href="../css/index.css" rel="stylesheet" />
<link href="/css/layers.css" rel="stylesheet" /> <link href="../css/layers.css" rel="stylesheet" />
<link href="/css/ui/generic.css" rel="stylesheet" /> <link href="../css/ui/generic.css" rel="stylesheet" />
<link href="/css/ui/history.css" rel="stylesheet" /> <link href="../css/ui/history.css" rel="stylesheet" />
<link href="/css/ui/layers.css" rel="stylesheet" /> <link href="../css/ui/layers.css" rel="stylesheet" />
<link href="/css/ui/toolbar.css" rel="stylesheet" /> <link href="../css/ui/toolbar.css" rel="stylesheet" />
<!-- Tool Specific CSS --> <!-- Tool Specific CSS -->
<link href="/css/ui/tool/dream.css" rel="stylesheet" /> <link href="../css/ui/tool/dream.css" rel="stylesheet" />
<link href="/css/ui/tool/stamp.css" rel="stylesheet" /> <link href="../css/ui/tool/stamp.css" rel="stylesheet" />
<link href="/css/ui/tool/colorbrush.css" rel="stylesheet" /> <link href="../css/ui/tool/colorbrush.css" rel="stylesheet" />
<link rel="icon" type="image/x-icon" href="favicon.ico" /> <link rel="icon" type="image/x-icon" href="favicon.ico" />
@ -65,14 +65,21 @@
const canvasHeight = document.getElementById("canvas-height"); const canvasHeight = document.getElementById("canvas-height");
function writeToLocalStorage() { function writeToLocalStorage() {
localStorage.setItem("settings.canvas-width", canvasWidth.value); localStorage.setItem(
localStorage.setItem("settings.canvas-height", canvasHeight.value); "openoutpaint/settings.canvas-width",
canvasWidth.value
);
localStorage.setItem(
"openoutpaint/settings.canvas-height",
canvasHeight.value
);
} }
// Loads values from local storage // Loads values from local storage
canvasWidth.value = localStorage.getItem("settings.canvas-width") || 2048; canvasWidth.value =
localStorage.getItem("openoutpaint/settings.canvas-width") || 2048;
canvasHeight.value = canvasHeight.value =
localStorage.getItem("settings.canvas-height") || 2048; localStorage.getItem("openoutpaint/settings.canvas-height") || 2048;
writeToLocalStorage(); writeToLocalStorage();