Skip to content

Commit 374fe63

Browse files
committed
Squashed commit of the following:
commit b030b67 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Wed Feb 8 16:38:56 2023 -0800 styling adjustements commit 80a2acb Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Wed Feb 8 10:49:47 2023 -0800 badge indicator toggles visibility by selection commit 898922e Merge: 745382a 31bbfa7 Author: Gerschel <9631031+Gerschel@users.noreply.github.com> Date: Wed Feb 8 08:35:26 2023 -0800 Merge pull request heiko-hotz#1 from w-e-w/Rounding-Method Rounding Method commit 31bbfa7 Author: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Wed Feb 8 19:41:45 2023 +0900 use switch commit 85dbe51 Author: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Wed Feb 8 16:47:52 2023 +0900 Rounding Method commit 745382a Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 21:19:20 2023 -0800 default set to round commit 728579c Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 21:17:03 2023 -0800 cleaned some commented code out; added indicator commit 5b288c2 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 18:19:00 2023 -0800 needs cleaning; attempt at rounding commit d9f18ae Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 15:46:25 2023 -0800 add rounding option in setting for aspect ratio commit af22106 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 13:18:45 2023 -0800 added some ratios, sorted ratios by commonality commit 11e2fba Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 10:46:53 2023 -0800 snaps to mulitples of 8 and along ratio commit fa00387 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:54:59 2023 -0800 updated slidercomponentcontroller commit 8059bc1 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:29:11 2023 -0800 added step size adjustment on number field commit 641157b Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:12:03 2023 -0800 added return step size to default when ratio is disabled commit 5fb75ad Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:09:34 2023 -0800 added step size adjustment commit e335328 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 11:56:15 2023 -0800 adjusted dropdown size, padding, text-align commit 8193732 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 11:39:57 2023 -0800 added positioning and styling commit 86eb458 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 08:54:45 2023 -0800 fix typo in defaults; added preventDefault in event
1 parent 5d483bf commit 374fe63

5 files changed

Lines changed: 218 additions & 21 deletions

File tree

javascript/ComponentControllers.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ class SliderComponentController {
189189
}
190190
eventHandler() {
191191
this.element.dispatchEvent(new Event("input"));
192+
this.childNumField.dispatchEvent(new Event("input"));
193+
this.childRangeField.dispatchEvent(new Event("input"));
192194
}
193195
setVal(text) {
194196
this.updateVal(text);

javascript/aspectRatioSliders.js

Lines changed: 152 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,181 @@
11
class AspectRatioSliderController {
2-
constructor(widthSlider, heightSlider, ratioSource) {
2+
constructor(widthSlider, heightSlider, ratioSource, roundingSource, roundingMethod) {
3+
//References
34
this.widthSlider = new SliderComponentController(widthSlider);
45
this.heightSlider = new SliderComponentController(heightSlider);
56
this.ratioSource = new DropdownComponentController(ratioSource);
6-
this.widthSlider.childRangeField.addEventListener("change", () => this.resize("width"));
7-
this.widthSlider.childNumField.addEventListener("change", () => this.resize("width"));
8-
this.heightSlider.childRangeField.addEventListener("change", () => this.resize("height"));
9-
this.heightSlider.childNumField.addEventListener("change", () => this.resize("height"));
7+
this.roundingSource = new CheckboxComponentController(roundingSource);
8+
this.roundingMethod = new RadioComponentController(roundingMethod);
9+
this.roundingIndicatorBadge = document.createElement("div");
10+
// Badge implementation
11+
this.roundingIndicatorBadge.innerText = "📐";
12+
this.roundingIndicatorBadge.classList.add("rounding-badge");
13+
this.ratioSource.element.appendChild(this.roundingIndicatorBadge);
14+
// Check initial value of ratioSource to set badge visbility
15+
let initialRatio = this.ratioSource.getVal();
16+
if (!initialRatio.includes(":")) {
17+
this.roundingIndicatorBadge.style.display = "none";
18+
}
19+
//Adjust badge icon if rounding is on
20+
if (this.roundingSource.getVal()) {
21+
this.roundingIndicatorBadge.classList.add("active");
22+
this.roundingIndicatorBadge.innerText = "⚠️";
23+
}
24+
//Make badge clickable to toggle setting
25+
this.roundingIndicatorBadge.addEventListener("click", () => {
26+
this.roundingSource.setVal(!this.roundingSource.getVal());
27+
});
28+
//Make rounding setting toggle badge text and style if setting changes
29+
this.roundingSource.child.addEventListener("change", () => {
30+
if (this.roundingSource.getVal()) {
31+
this.roundingIndicatorBadge.classList.add("active");
32+
this.roundingIndicatorBadge.innerText = "⚠️";
33+
}
34+
else {
35+
this.roundingIndicatorBadge.classList.remove("active");
36+
this.roundingIndicatorBadge.innerText = "📐";
37+
}
38+
this.adjustStepSize();
39+
});
40+
//Other event listeners
41+
this.widthSlider.childRangeField.addEventListener("change", (e) => { e.preventDefault(); this.resize("width"); });
42+
this.widthSlider.childNumField.addEventListener("change", (e) => { e.preventDefault(); this.resize("width"); });
43+
this.heightSlider.childRangeField.addEventListener("change", (e) => { e.preventDefault(); this.resize("height"); });
44+
this.heightSlider.childNumField.addEventListener("change", (e) => { e.preventDefault(); this.resize("height"); });
45+
this.ratioSource.childSelector.addEventListener("change", (e) => {
46+
e.preventDefault();
47+
//Check and toggle display of badge conditionally on dropdown selection
48+
if (!this.ratioSource.getVal().includes(":")) {
49+
this.roundingIndicatorBadge.style.display = 'none';
50+
}
51+
else {
52+
this.roundingIndicatorBadge.style.display = 'block';
53+
}
54+
this.adjustStepSize();
55+
});
1056
}
1157
resize(dimension) {
58+
//For moving slider or number field
1259
let val = this.ratioSource.getVal();
1360
if (!val.includes(":")) {
1461
return;
1562
}
1663
let [width, height] = val.split(":").map(Number);
1764
let ratio = width / height;
1865
if (dimension == 'width') {
19-
this.heightSlider.setVal(Math.round(parseFloat(this.widthSlider.getVal()) / ratio).toString());
66+
let newHeight = parseInt(this.widthSlider.getVal()) / ratio;
67+
if (this.roundingSource.getVal()) {
68+
switch (this.roundingMethod.getVal()) {
69+
case 'Round':
70+
newHeight = Math.round(newHeight / 8) * 8;
71+
break;
72+
case 'Ceiling':
73+
newHeight = Math.ceil(newHeight / 8) * 8;
74+
break;
75+
case 'Floor':
76+
newHeight = Math.floor(newHeight / 8) * 8;
77+
break;
78+
}
79+
}
80+
this.heightSlider.setVal(newHeight.toString());
2081
}
2182
else if (dimension == "height") {
22-
this.widthSlider.setVal(Math.round(parseFloat(this.heightSlider.getVal()) * ratio).toString());
83+
let newWidth = parseInt(this.heightSlider.getVal()) * ratio;
84+
if (this.roundingSource.getVal()) {
85+
switch (this.roundingMethod.getVal()) {
86+
case 'Round':
87+
newWidth = Math.round(newWidth / 8) * 8;
88+
break;
89+
case 'Ceiling':
90+
newWidth = Math.ceil(newWidth / 8) * 8;
91+
break;
92+
case 'Floor':
93+
newWidth = Math.floor(newWidth / 8) * 8;
94+
break;
95+
}
96+
}
97+
this.widthSlider.setVal(newWidth.toString());
98+
}
99+
}
100+
adjustStepSize() {
101+
/* Sets scales/precision/rounding steps;*/
102+
let val = this.ratioSource.getVal();
103+
if (!val.includes(":")) {
104+
//If ratio unlocked
105+
this.widthSlider.childRangeField.step = "8";
106+
this.widthSlider.childRangeField.min = "64";
107+
this.widthSlider.childNumField.step = "8";
108+
this.widthSlider.childNumField.min = "64";
109+
this.heightSlider.childRangeField.step = "8";
110+
this.heightSlider.childRangeField.min = "64";
111+
this.heightSlider.childNumField.step = "8";
112+
this.heightSlider.childNumField.min = "64";
113+
return;
114+
}
115+
//Format string and calculate step sizes
116+
let [width, height] = val.split(":").map(Number);
117+
let decimalPlaces = (width.toString().split(".")[1] || []).length;
118+
//keep upto 6 decimal points of precision of ratio
119+
//euclidean gcd does not support floats, so we scale it up
120+
decimalPlaces = decimalPlaces > 6 ? 6 : decimalPlaces;
121+
let gcd = this.gcd(width * 10 ** decimalPlaces, height * 10 ** decimalPlaces) / 10 ** decimalPlaces;
122+
let stepSize = 8 * height / gcd;
123+
let stepSizeOther = 8 * width / gcd;
124+
if (this.roundingSource.getVal()) {
125+
//If rounding is on set/keep default stepsizes
126+
this.widthSlider.childRangeField.step = "8";
127+
this.widthSlider.childRangeField.min = "64";
128+
this.widthSlider.childNumField.step = "8";
129+
this.widthSlider.childNumField.min = "64";
130+
this.heightSlider.childRangeField.step = "8";
131+
this.heightSlider.childRangeField.min = "64";
132+
this.heightSlider.childNumField.step = "8";
133+
this.heightSlider.childNumField.min = "64";
134+
}
135+
else {
136+
//if rounding is off, set step sizes so they enforce snapping
137+
//min is changed, because it offsets snap positions
138+
this.widthSlider.childRangeField.step = stepSizeOther.toString();
139+
this.widthSlider.childRangeField.min = stepSizeOther.toString();
140+
this.widthSlider.childNumField.step = stepSizeOther.toString();
141+
this.widthSlider.childNumField.min = stepSizeOther.toString();
142+
this.heightSlider.childRangeField.step = stepSize.toString();
143+
this.heightSlider.childRangeField.min = stepSize.toString();
144+
this.heightSlider.childNumField.step = stepSize.toString();
145+
this.heightSlider.childNumField.min = stepSize.toString();
146+
}
147+
let currentWidth = parseInt(this.widthSlider.getVal());
148+
//Rounding treated kinda like pythons divmod
149+
let stepsTaken = Math.round(currentWidth / stepSizeOther);
150+
//this snaps it to closest rule matches (rules being html step points, and ratio)
151+
let newWidth = stepsTaken * stepSizeOther;
152+
this.widthSlider.setVal(newWidth.toString());
153+
this.heightSlider.setVal(Math.round(newWidth / (width / height)).toString());
154+
}
155+
gcd(a, b) {
156+
//euclidean gcd
157+
if (b === 0) {
158+
return a;
23159
}
160+
return this.gcd(b, a % b);
24161
}
25-
static observeStartup(widthSliderId, heightSliderId, ratioSourceId) {
162+
static observeStartup(widthSliderId, heightSliderId, ratioSourceId, roundingSourceId, roundingMethodId) {
26163
let observer = new MutationObserver(() => {
27164
let widthSlider = document.querySelector("gradio-app").shadowRoot.getElementById(widthSliderId);
28165
let heightSlider = document.querySelector("gradio-app").shadowRoot.getElementById(heightSliderId);
29166
let ratioSource = document.querySelector("gradio-app").shadowRoot.getElementById(ratioSourceId);
30-
if (widthSlider && heightSlider && ratioSource) {
167+
let roundingSource = document.querySelector("gradio-app").shadowRoot.getElementById(roundingSourceId);
168+
let roundingMethod = document.querySelector("gradio-app").shadowRoot.getElementById(roundingMethodId);
169+
if (widthSlider && heightSlider && ratioSource && roundingSource && roundingMethod) {
31170
observer.disconnect();
32-
new AspectRatioSliderController(widthSlider, heightSlider, ratioSource);
171+
new AspectRatioSliderController(widthSlider, heightSlider, ratioSource, roundingSource, roundingMethod);
33172
}
34173
});
35174
observer.observe(gradioApp(), { childList: true, subtree: true });
36175
}
37176
}
38177
document.addEventListener("DOMContentLoaded", () => {
39-
AspectRatioSliderController.observeStartup("txt2img_width", "txt2img_height", "txt2img_ratio");
40-
AspectRatioSliderController.observeStartup("img2img_width", "img2img_height", "img2img_ratio");
178+
//Register mutation observer for self start-up;
179+
AspectRatioSliderController.observeStartup("txt2img_width", "txt2img_height", "txt2img_ratio", "setting_aspect_ratios_rounding", "setting_aspect_ratios_rounding_method");
180+
AspectRatioSliderController.observeStartup("img2img_width", "img2img_height", "img2img_ratio", "setting_aspect_ratios_rounding", "setting_aspect_ratios_rounding_method");
41181
});

modules/shared.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,21 @@
140140
]
141141

142142
aspect_ratio_defaults = [
143-
"🔓"
143+
"🔓",
144144
"1:1",
145-
"1:2",
146-
"2:1",
147-
"2:3",
148145
"3:2",
149146
"4:3",
150147
"5:4",
151-
"9:16",
152148
"16:9",
149+
"9:16",
150+
"1.85:1",
151+
"2.35:1",
152+
"2.39:1",
153+
"2.40:1",
154+
"21:9",
155+
"1.375:1",
156+
"1.66:1",
157+
"1.75:1"
153158
]
154159

155160
cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or cmd_opts.server_name) and not cmd_opts.enable_insecure_extension_access
@@ -469,6 +474,8 @@ def list_samplers():
469474
"keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
470475
"quicksettings": OptionInfo("sd_model_checkpoint", "Quicksettings list"),
471476
"ui_reorder": OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"),
477+
"aspect_ratios_rounding": OptionInfo(True, "Round aspect ratios for more flexibility?", gr.Checkbox),
478+
"aspect_ratios_rounding_method": OptionInfo("Ceiling", "Aspect ratios rounding method", gr.Radio,{"choices": ["Round", "Ceiling", "Floor"]}),
472479
"aspect_ratios": OptionInfo(", ".join(aspect_ratio_defaults), "txt2img/img2img aspect ratios"),
473480
"ui_extra_networks_tab_reorder": OptionInfo("", "Extra networks tab order"),
474481
"localization": OptionInfo("None", "Localization (requires restart)", gr.Dropdown, lambda: {"choices": ["None"] + list(localization.localizations.keys())}, refresh=lambda: localization.list_localizations(cmd_opts.localizations_dir)),

modules/ui.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,9 @@ def create_ui():
483483
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width")
484484
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")
485485

486-
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn")
487-
aspect_ratio_dropdown = gr.Dropdown(value="🔓", choices=aspect_ratio_list(), interactive=True, type="value", elem_id="txt2img_ratio", show_label=False, label="Aspect Ratio")
486+
with gr.Column(elem_id="txt2img_size_toolbox", scale=0):
487+
aspect_ratio_dropdown = gr.Dropdown(value="🔓", choices=aspect_ratio_list(), interactive=True, type="value", elem_id="txt2img_ratio", show_label=False, label="Aspect Ratio")
488+
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn")
488489
if opts.dimensions_and_batch_together:
489490
with gr.Column(elem_id="txt2img_column_batch"):
490491
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
@@ -762,8 +763,9 @@ def copy_image(img):
762763
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width")
763764
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
764765

765-
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
766-
aspect_ratio_dropdown = gr.Dropdown(value="🔓", choices=aspect_ratio_list(), interactive=True, type="value", elem_id="img2img_ratio", show_label=False, label="Aspect Ratio")
766+
with gr.Column(elem_id="img2img_size_toolbox", scale=0):
767+
aspect_ratio_dropdown = gr.Dropdown(value="🔓", choices=aspect_ratio_list(), interactive=True, type="value", elem_id="img2img_ratio", show_label=False, label="Aspect Ratio")
768+
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
767769
if opts.dimensions_and_batch_together:
768770
with gr.Column(elem_id="img2img_column_batch"):
769771
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")

style.css

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,52 @@ footer {
747747
margin-left: 0em;
748748
}
749749

750+
#txt2img_size_toolbox, #img2img_size_toolbox{
751+
min-width: unset !important;
752+
gap: 0;
753+
}
754+
755+
#txt2img_ratio, #img2img_ratio {
756+
padding: 0px;
757+
min-width: unset;
758+
max-width: fit-content;
759+
}
760+
#txt2img_ratio select, #img2img_ratio select{
761+
-o-appearance: none;
762+
-ms-appearance: none;
763+
-webkit-appearance: none;
764+
-moz-appearance: none;
765+
appearance: none;
766+
background-image: unset;
767+
padding-right: unset;
768+
min-width: 40px;
769+
max-width: 40px;
770+
min-height: 40px;
771+
max-height: 40px;
772+
line-height: 40px;
773+
padding: 0;
774+
text-align: center;
775+
}
776+
.rounding-badge {
777+
display: inline-block;
778+
border-radius: 0px;
779+
background-color: #ccc;
780+
cursor: pointer;
781+
position: absolute;
782+
top: -10px;
783+
right: -10px;
784+
width: 20px;
785+
height: 20px;
786+
padding: 1px;
787+
line-height: 16px;
788+
font-size: 14px;
789+
}
790+
791+
.rounding-badge.active {
792+
background-color: #007bff;
793+
border-radius: 50%;
794+
}
795+
750796
.inactive{
751797
opacity: 0.5;
752798
}

0 commit comments

Comments
 (0)