From 4d3f55622abc544a62ecb0e75e97a517eba3d18d Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sat, 29 Jul 2023 18:12:48 +0200 Subject: [PATCH] Support more image sizes (#1441) * Support more image sizes With diffusers, width and height must be a multiple of 8 (instead of 64), allowing more resolution values. * Add swap button * Change popup button icon --- ui/index.html | 57 +++++------------ ui/media/css/main.css | 33 ++++++++++ ui/media/js/main.js | 125 ++++++++++++++++++++++++++++++++++++++ ui/media/js/parameters.js | 4 ++ 4 files changed, 176 insertions(+), 43 deletions(-) diff --git a/ui/index.html b/ui/index.html index 2d47433e..59b74cb3 100644 --- a/ui/index.html +++ b/ui/index.html @@ -191,51 +191,22 @@ Click to learn more about samplers - - + + - + Swap width and height + +
+ Recent sizes +
+ Upscale:
+   
+ Recently used:
+
+
+
+
Small image sizes can cause bad image quality
diff --git a/ui/media/css/main.css b/ui/media/css/main.css index 41c6f196..53424f53 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1754,6 +1754,38 @@ body.wait-pause { font-size: 10pt; } +input#width, input#height { + width: 47pt; +} + +div#recent-resolutions-container { + position: relative; + display:inline-block; +} + +div#recent-resolutions-popup { + position: absolute; + right: 0px; + margin: 3px; + padding: 0.2em 1em 0.4em 1em; + z-index: 1; + background: var(--background-color3); + border-radius: 4px; + box-shadow: 0 20px 28px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15); +} + +div#recent-resolutions-popup small { + opacity: 0.7; +} + +td#image-size-options small { + margin-right: 0px !important; +} + +.clickable { + cursor: pointer; +} + .imgContainer .spinner { position: absolute; left: 50%; @@ -1769,6 +1801,7 @@ body.wait-pause { border: 1px solid var(--button-color); box-shadow: 0px 0px 4px black; } + .imgContainer .spinnerStatus { font-size: 10pt; } diff --git a/ui/media/js/main.js b/ui/media/js/main.js index fa42d3ff..67d4a251 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -77,6 +77,13 @@ let randomSeedField = document.querySelector("#random_seed") let seedField = document.querySelector("#seed") let widthField = document.querySelector("#width") let heightField = document.querySelector("#height") +let recentResolutionsButton = document.querySelector("#recent-resolutions-button") +let recentResolutionsPopup = document.querySelector("#recent-resolutions-popup") +let recentResolutionList = document.querySelector("#recent-resolution-list") +let upscale15Button = document.querySelector("#upscale15") +let upscale2Button = document.querySelector("#upscale2") +let upscale3Button = document.querySelector("#upscale3") +let swapWidthHeightButton = document.querySelector("#swap-width-height") let smallImageWarning = document.querySelector("#small_image_warning") let initImageSelector = document.querySelector("#init_image") let initImagePreview = document.querySelector("#init_image_preview") @@ -2570,3 +2577,121 @@ createLoraEntries() // } // document.querySelectorAll("input[type=number]").forEach(showSpinnerOnlyOnHover) + +////////////////////////////// Image Size Widget ////////////////////////////////////////// + +function roundToMultiple(number, n) { + if (n=="") { n=1 } + return Math.round(number / n) * n; +} + +function upscaleImageSize(factor) { + let step = width.step + width.value = roundToMultiple(width.value*factor, step) + height.value = roundToMultiple(height.value*factor, step) +} + + +function makeResolutionButtons() { + recentResolutionList.innerHTML = "" + recentResolutionsValues.forEach( el => { + let button = document.createElement("button") + button.classList.add("tertiaryButton") + button.style.width="8em" + button.innerHTML = `${el.w}×${el.h}` + button.addEventListener("click", () => { + width.value=el.w + height.value=el.h + width.dispatchEvent(new Event("change")) + height.dispatchEvent(new Event("change")) + recentResolutionsPopup.classList.add("displayNone") + }) + recentResolutionList.appendChild(button) + recentResolutionList.appendChild(document.createElement("br")) + }) + localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues) +} + +let recentResolutionsValues = [] + +;(function() { ///// Init resolutions dropdown + upscale15Button.addEventListener("click", () => { + upscaleImageSize(1.5) + recentResolutionsPopup.classList.add("displayNone") + }) + + upscale2Button.addEventListener("click", () => { + upscaleImageSize(2) + recentResolutionsPopup.classList.add("displayNone") + }) + + upscale3Button.addEventListener("click", () => { + upscaleImageSize(3) + recentResolutionsPopup.classList.add("displayNone") + }) + + width.addEventListener("change", () => { + let w = width.value + width.value = roundToMultiple(w, width.step) + if (w!=width.value) { + showToast(`Rounded width to the closest multiple of ${width.step}.`) + } + }) + + height.addEventListener("change", () => { + let h = height.value + height.value = roundToMultiple(h, height.step) + if (h!=height.value) { + showToast(`Rounded height to the closest multiple of ${height.step}.`) + } + }) + + makeImageBtn.addEventListener("click", () => { + let w = width.value + let h = height.value + + recentResolutionsValues = recentResolutionsValues.filter(el => (el.w!=w || el.h!=h)) + recentResolutionsValues.unshift({w: w, h:h}) + recentResolutionsValues = recentResolutionsValues.slice(0,8) + + localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues) + makeResolutionButtons() + }) + + let _jsonstring = localStorage.recentResolutionsValues + if (_jsonstring==undefined) { + recentResolutionsValues = [ + {w:512,h:512}, + {w:640,h:448}, + {w:448,h:640}, + {w:512,h:768}, + {w:768,h:512}, + {w:1024,h:768}, + {w:768,h:1024}, + ] + localStorage.recentResolutionsValues = JSON.stringify(recentResolutionsValues) + } else { + recentResolutionsValues = JSON.parse(localStorage.recentResolutionsValues) + } + makeResolutionButtons() + + function processClick(e) { + if (!recentResolutionsPopup.contains(e.target)) { + recentResolutionsPopup.classList.add("displayNone") + } + document.removeEventListener("click", processClick) + } + + recentResolutionsButton.addEventListener("click", (event) => { + recentResolutionsPopup.classList.toggle("displayNone") + event.stopPropagation() + document.addEventListener("click", processClick) + }) + + swapWidthHeightButton.addEventListener("click", (event) => { + let temp = width.value + width.value = height.value + height.value = temp + }) +})() + diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index 1980f1a1..0dae628b 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -453,6 +453,8 @@ async function getAppConfig() { document.querySelectorAll("#sampler_name option.diffusers-only").forEach((option) => { option.style.display = "none" }) + width.step=64 + height.step=64 } else { document.querySelector("#lora_model_container").style.display = "" document.querySelector("#tiling_container").style.display = "" @@ -463,6 +465,8 @@ async function getAppConfig() { document.querySelector("#clip_skip_config").classList.remove("displayNone") document.querySelector("#embeddings-button").classList.remove("displayNone") document.querySelector("#negative-embeddings-button").classList.remove("displayNone") + width.step=8 + height.step=8 } console.log("get config status response", config)