├── .gitignore
├── README.md
├── javascript
└── sd-webui-ar-plusplus.js
├── scripts
└── sd-webui-ar-plusplus.py
└── style.css
/.gitignore:
--------------------------------------------------------------------------------
1 | **/*.swp
2 | **/.mypy_cache
3 | *.py[cod]
4 | aspect_ratios.txt
5 | resolutions.txt
6 | button_titles.js
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Stable Diffusion WebUI Aspect Ratio and Resolution Buttons
2 |
3 | Extension for [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui.git) and [stable-diffusion-webui-forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) adding image aspect ratio selector buttons.
4 |
5 | ---
6 |
7 | ## Main Fork feature
8 |
9 |
10 |
11 | #### Uses an enhanced method to calculate the width/height values when clicking Aspect Ratio buttons.
12 |
13 | - Gets the mean value (average) of the current **width** and **height** values in the UI.
14 |
15 | - For the selected aspect ratio, the dimensions are offset equally (positively and negatively) from the average, ensuring nearest total pixel count to user's initial resolution.
16 |
17 | - Uses the same precision rounding method as [Stability-AI/StableSwarmUI](https://github.com/Stability-AI/StableSwarmUI/blob/4ef98019fc4796d69f0d1d2dfa487d684a748cc3/src/Utils/Utilities.cs#L573) when updating image dimensions.
18 |
19 | - "Mode" button allows switching to use calculation method from [LEv145/--sd-webui-ar-plus](https://github.com/LEv145/--sd-webui-ar-plus) (Only update Width OR Height)
20 |
21 | ---
22 |
23 |
24 |
25 | ---
26 |
27 | #### For best results switching between aspect ratios, pick a static res value (such as 1024, etc), then press the "Lock" button to lock in an average res.
28 |
29 | - The calculation method works correctly in all cases
30 |
31 | - However, since the output values are rounded to the nearest division of 64, the mean value (average) of the input values will change when "Unlocked".
32 |
33 | ---
34 |
35 |
36 |
37 | ---
38 |
39 | #### The original "Calculator panel" has been replaced with an information panel:
40 |
41 | - Current average is displayed for reference.
42 |
43 | - Rounding precision can be adjusted with default value of 64px.
44 |
45 | ---
46 |
47 | ## Installation
48 |
49 | 1. Navigate to the Extensions tab in [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui.git) or [stable-diffusion-webui-forge](https://github.com/lllyasviel/stable-diffusion-webui-forge)
50 |
51 | 2. Click "Install from URL"
52 |
53 | 3. Copy/Paste this repository into the "URL for extension's git repository" field and click "Install"
54 | ```
55 | https://github.com/altoiddealer/--sd-webui-ar-plusplus
56 | ```
57 |
58 |
59 |
60 |
61 | 4. Return to the "Installed" tab and click "Apply and restart UI"
62 |
63 |
64 |
65 |
66 | ---
67 |
68 |
69 |
70 | Details from [the source project (LEv145/--sd-webui-ar-plus)
71 |
72 | # Details from [the source project](https://github.com/LEv145/--sd-webui-ar-plus) (LEv145/--sd-webui-ar-plus)
73 |
74 | (For reference - much of this is obsolete)
75 |
76 | ## Fork features
77 |
78 | - New button `🔃` for calculation of height and width inverse
79 | - Normal mode: `1024x1024 and 16:9 = 1820x1024`
80 | - Reverse mode: `1024x1024 and 16:9 = 1024x576`
81 | - New button `🔍` for rounding dimensions to the nearest multiples of 4 (`1023x101` => `1024x100`)
82 | - New styles (Some styles have been moved to the original extension)
83 | - Better resolution presets (By formula: `f(x) = 512 + (1024-512)/4*x, 0 <= x <= 4`)
84 | - Better ratios presets (From [wikipedia](https://en.wikipedia.org/wiki/Aspect_ratio_(image)))
85 | - Rename `Calc` button to `📐`
86 | - Can work together with the original extension
87 |
88 |
89 | ## Updates
90 |
91 | - 20/02/2023 :warning: this update will remove your local config files (`aspect_ratios.txt` and `resolutions.txt`) and it will create new default ones. These can be then modified freely and preserved in the future. For more info read [here](https://github.com/alemelis/sd-webui-ar/issues/9).
92 |
93 | ## Install
94 |
95 | Browse to the `Extensions` tab -> go to `Install from URL` -> paste in `https://github.com/alemelis/sd-webui-ar` -> click `Install`
96 |
97 |
98 | Here's how the UI looks like after installing this extension
99 |
100 |
101 |
102 | ## Usage
103 |
104 | - Click on the aspect ratio button you want to set. In the case of an aspect ratio greater than 1, the script fixes the width and changes the height. Whereas if the aspect ratio is smaller than 1, the width changes while the height is fixed.
105 | - Reset image resolution by clicking on one of the buttons on the second row.
106 |
107 | ### Configuration
108 |
109 | Aspect ratios can be defined in the `/sd-webui-ar/aspect_ratios.txt` file. For example,
110 |
111 | ```
112 | 1:1, 1.0
113 | 3:2, 3/2
114 | 4:3, 4/3
115 | 16:9, 16/9
116 | # 6:13, 6/13
117 | # 9:16, 9/16
118 | # 3:5, 3/5
119 | # 2:3, 2/3
120 | # 19:16, 19/16 # fox movietone
121 | # 5:4, 5/4 # medium format photo
122 | # 11:8, 11/8 # academy standard
123 | # IMAX, 1.43
124 | # 14:9, 14/9
125 | # 16:10, 16/10
126 | # 𝜑, 1.6180 # golden ratio
127 | # 5:3, 5/3 # super 16mm
128 | # 1.85, 1.85 # US widescreen cinema
129 | # DCI, 1.9 # digital imax
130 | # 2:1, 2.0 # univisium
131 | # 70mm, 2.2
132 | # 21:9, 21/9 # cinematic wide screen
133 | # δ, 2.414 # silver ratio
134 | # UPV70, 2.76 # ultra panavision 70
135 | # 32:9, 32/9 # ultra wide screen
136 | # PV, 4.0 # polyvision
137 | ```
138 |
139 | Note the `#` marking the line as a comment, i.e. the extension is not reading that line. To use a custom value, un-comment the relative line by removing the starting `#`.
140 | A custom aspect ratio is defined as `button-label, aspect-ratio-value # comment`. It is recommended to set the `aspect-ratio-value` to a fraction, but a `float` or `int` will work as well. The `# comment` is optional.
141 | The `button-label` will be displayed inside the button. It can be anything you like.
142 |
143 | Resolutions presets are defined inside `resolutions.txt` file,
144 |
145 | ```
146 | 1, 512, 512 # 1:1 square
147 | 2, 768, 512 # 3:2 landscape
148 | 3, 403, 716 # 9:16 portrait
149 | ```
150 |
151 | The format to be used is `button-label, width, height, # optional comment`. As before, lines starting with `#` will be ignored.
152 |
153 | ## Calculator Panel
154 | Use the calculator to determine new width or height values based on the aspect ratio of source dimensions.
155 | - Click `Calc` to show or hide the aspect ratio calculator
156 | - Set the source dimensions:
157 | - Enter manually, or
158 | - Click ⬇️ to get source dimentions from txt2img/img2img sliders, or
159 | - Click 🖼️ to get source dimensions from input image component on the current tab
160 | - Click ⇅ to swap the width and height, if desired
161 | - Set the desired width or height, then click either `Calculate Height` or `Calculate Width` to calculate the missing value
162 | - Click `Apply` to send the values to the txt2txt/img2img sliders
163 | ---
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/javascript/sd-webui-ar-plusplus.js:
--------------------------------------------------------------------------------
1 | if ("undefined" === typeof arsp__ar_button_titles) {
2 | arsp__ar_button_titles = {};
3 | }
4 |
5 | arsp__ar_button_titles[" \u{1F513}"] = 'Toggle to lock the "average" width/height values in the UI\nIt is recommended to "Lock" when switching between ARs in "Offset" mode.\n\n\u{1F512} = Locked\n\u{1F513} = Unlocked';
6 | arsp__ar_button_titles[" \u{025AD}"] = 'For "Offset mode" (default):\n\u{025AF} = Portrait resolutions\n\u{025AD} = Landscape resolutions\n\nFor "One Dimension" mode:\n\u{025AD} = Modify Width\n\u{025AF} = Modify Height';
7 | arsp__ar_button_titles[" \u{02B83}"] = 'Toggle the Mode for updating resolution.\nResolution is always rounded to precision (default 64px).\n\n\u{02B83} = "Offset" updates both Width/Height from the average current resolution\n\u{02B85} = "One Dimension" changes only Width or Height';
8 | arsp__ar_button_titles[" \u{02139}"] = 'Show the Information panel including additional settings.'
9 | arsp__ar_button_titles[" \u{02BC5}"] = 'Hide the Information panel.'
10 |
11 | onUiUpdate(function(){
12 | gradioApp().querySelectorAll('#arsp__txt2img_container_aspect_ratio button, #arsp__img2img_container_aspect_ratio button').forEach(function(elem){
13 | tooltip = arsp__ar_button_titles[elem.textContent];
14 | if(tooltip){
15 | elem.title = tooltip;
16 | }
17 | })
18 | })
--------------------------------------------------------------------------------
/scripts/sd-webui-ar-plusplus.py:
--------------------------------------------------------------------------------
1 | import typing as t
2 | import contextlib
3 | from pathlib import Path
4 |
5 | import gradio as gr
6 |
7 | import modules.scripts as scripts
8 | from modules.ui_components import ToolButton
9 |
10 | from fractions import Fraction
11 | from math import sqrt
12 |
13 | BASE_PATH = scripts.basedir()
14 |
15 | class ButtonState():
16 | def __init__(self):
17 | self.is_locked = False
18 | self.switched = False
19 | self.alt_mode = False
20 | def toggle_lock(self):
21 | self.is_locked = not self.is_locked
22 | def toggle_switch(self):
23 | self.switched = not self.switched
24 | def toggle_mode(self):
25 | self.alt_mode = not self.alt_mode
26 |
27 | txt2img_state = ButtonState()
28 | img2img_state = ButtonState()
29 |
30 | # Helper functions for calculating new width/height values
31 | def round_to_precision(val, prec):
32 | return round(val / prec) * prec
33 |
34 | def res_to_model_fit(avg, w, h, prec):
35 | mp = w * h
36 | mp_target = avg * avg
37 | scale = sqrt(mp_target / mp)
38 | w = int(round_to_precision(w * scale, prec))
39 | h = int(round_to_precision(h * scale, prec))
40 | return w, h
41 |
42 | def calc_width(n, d, w, h, prec):
43 | ar = round((n / d), 2) # Convert AR parts to fraction
44 | if ar > 1.0:
45 | h = w / ar
46 | elif ar < 1.0:
47 | w = h * ar
48 | else:
49 | new_value = max([w, h])
50 | w, h = new_value, new_value
51 | w = int(round_to_precision((w + prec / 2), prec))
52 | h = int(round_to_precision((h + prec / 2), prec))
53 | return w, h
54 |
55 | def calc_height(n, d, w, h, prec):
56 | ar = round((n / d), 2) # Convert AR parts to fraction
57 | if ar > 1.0:
58 | w = h * ar
59 | elif ar < 1.0:
60 | h = w / ar
61 | else:
62 | new_value = min([w, h])
63 | w, h = new_value, new_value
64 | w = int(round_to_precision((w + prec / 2), prec))
65 | h = int(round_to_precision((h + prec / 2), prec))
66 | return w, h
67 |
68 | def dims_from_ar(avg, n, d, prec):
69 | doubleavg = avg * 2
70 | ar_sum = n+d
71 | # calculate width and height by factoring average with aspect ratio
72 | w = round((n / ar_sum) * doubleavg)
73 | h = round((d / ar_sum) * doubleavg)
74 | # Round to correct megapixel precision
75 | w, h = res_to_model_fit(avg, w, h, prec)
76 | return w, h
77 |
78 | def avg_from_dims(w, h):
79 | avg = (w + h) // 2
80 | if (w + h) % 2 != 0:
81 | avg += 1
82 | return avg
83 |
84 | ## Aspect Ratio buttons
85 | def create_ar_button_function(ar:str, is_img2img:bool):
86 | def wrapper(avg, prec, w=512, h=512):
87 | # Determine the state based on whether it's img2img or txt2img
88 | state = img2img_state if is_img2img else txt2img_state
89 |
90 | n, d = map(Fraction, ar.split(':')) # Split numerator and denominator
91 |
92 | if not state.is_locked:
93 | avg = avg_from_dims(w, h) # Get average of current width/height values
94 |
95 | if not state.alt_mode: # True = offset, False = One dimension
96 | w, h = dims_from_ar(avg, n, d, prec) # Calculate new w + h from avg, AR, and precision
97 | if state.switched: # Switch results if switch mode is active
98 | w, h = h, w
99 | else: # Calculate w or h from input, AR, and precision
100 | if state.switched: # Switch results if switch mode is active
101 | w, h = calc_width(n, d, w, h, prec) # Modify width
102 | else:
103 | w, h = calc_height(n, d, w, h, prec) # Modify height
104 |
105 | return avg, w, h
106 |
107 | return wrapper
108 |
109 | def create_ar_buttons(
110 | lst: t.Iterable[str],
111 | is_img2img: bool,
112 | ) -> t.Tuple[t.List[ToolButton], t.Dict[ToolButton, t.Callable]]:
113 | buttons = []
114 | functions = {}
115 |
116 | for ar in lst:
117 | button = ToolButton(ar, render=False)
118 | function = create_ar_button_function(ar, is_img2img)
119 | buttons.append(button)
120 | functions[button] = function
121 |
122 | return buttons, functions
123 |
124 | ## Static Resolution buttons
125 | def create_res_button_function(w:int, h:int, is_img2img:bool):
126 | def wrapper(avg):
127 | state = img2img_state if is_img2img else txt2img_state
128 | if not state.is_locked:
129 | avg = avg_from_dims(w, h)
130 | return avg, w, h
131 | return wrapper
132 |
133 | def create_res_buttons(
134 | lst: t.Iterable[t.Tuple[t.List[int], str]],
135 | is_img2img: bool,
136 | ) -> t.Tuple[t.List[ToolButton], t.Dict[ToolButton, t.Callable]]:
137 | buttons = []
138 | functions = {}
139 |
140 | for resolution, label in lst:
141 | button = ToolButton(label)
142 | w, h = resolution
143 | function = create_res_button_function(w, h, is_img2img)
144 | buttons.append(button)
145 | functions[button] = function
146 |
147 | return buttons, functions
148 |
149 | # Get values for Aspect Ratios from file
150 | def parse_aspect_ratios_file(filename):
151 | values, flipvals, comments = [], [], []
152 | file = Path(BASE_PATH, filename)
153 |
154 | if not file.exists():
155 | return values, comments, flipvals
156 |
157 | with open(file, "r", encoding="utf-8") as f:
158 | lines = f.readlines()
159 |
160 | if not lines:
161 | return values, comments, flipvals
162 |
163 | for line in lines:
164 | if line.startswith("#"):
165 | continue
166 |
167 | value = line.strip()
168 |
169 | comment = ""
170 | if "#" in value:
171 | value, comment = value.split("#")
172 | value = value.strip()
173 | values.append(value)
174 | comments.append(comment)
175 |
176 | comp1, comp2 = value.split(':')
177 | flipval = f"{comp2}:{comp1}"
178 | flipvals.append(flipval)
179 |
180 | return values, comments, flipvals
181 |
182 | # Get values for Static Resolutions from file
183 | def parse_resolutions_file(filename):
184 | labels, values, comments = [], [], []
185 | file = Path(BASE_PATH, filename)
186 |
187 | if not file.exists():
188 | return labels, values, comments
189 |
190 | with open(file, "r", encoding="utf-8") as f:
191 | lines = f.readlines()
192 |
193 | if not lines:
194 | return labels, values, comments
195 |
196 | for line in lines:
197 | if line.startswith("#"):
198 | continue
199 |
200 | label, width, height = line.strip().split(",")
201 | comment = ""
202 | if "#" in height:
203 | height, comment = height.split("#")
204 |
205 | resolution = (width, height)
206 |
207 | labels.append(label)
208 | values.append(resolution)
209 | comments.append(comment)
210 |
211 | return labels, values, comments
212 |
213 | def write_aspect_ratios_file(filename):
214 | aspect_ratios = [
215 | "1:1 # Square\n",
216 | "4:3 # Television Photography\n",
217 | "3:2 # Photography\n",
218 | "8:5 # Widescreen Displays\n",
219 | "16:9 # Widescreen Television\n",
220 | "21:9 # Ultrawide Cinematography"
221 | ]
222 | with open(filename, "w", encoding="utf-8") as f:
223 | f.writelines(aspect_ratios)
224 |
225 | def write_resolutions_file(filename):
226 | resolutions = [
227 | "512, 512, 512 # 512x512\n",
228 | "768, 768, 768 # 768x768\n",
229 | "1024, 1024, 1024 # 1024x1024\n",
230 | "1280, 1280, 1280 # 1280x1280\n",
231 | "1536, 1536, 1536 # 1536x1536\n",
232 | "2048, 2048, 2048 # 2048x2048",
233 | ]
234 | with open(filename, "w", encoding="utf-8") as f:
235 | f.writelines(resolutions)
236 |
237 | def write_js_titles_file(button_titles):
238 | filename = Path(BASE_PATH, "javascript", "button_titles.js")
239 | content = ["// Do not put custom titles here. This file is overwritten each time the WebUI is started.\n"]
240 | content.append("arsp__ar_button_titles = {\n")
241 | counter = 0
242 | while counter < len(button_titles[0]):
243 | content.append(f' " {button_titles[0][counter]}" : "{button_titles[1][counter]}",\n')
244 | counter = counter + 1
245 | content.append("}")
246 |
247 | with open(filename, "w", encoding="utf-8") as f:
248 | f.writelines(content)
249 |
250 | class AspectRatioScript(scripts.Script):
251 | def read_aspect_ratios(self):
252 | ar_file = Path(BASE_PATH, "aspect_ratios.txt")
253 | if not ar_file.exists():
254 | write_aspect_ratios_file(ar_file)
255 | (self.aspect_ratios, self.aspect_ratio_comments, self.flipped_vals) = parse_aspect_ratios_file("aspect_ratios.txt")
256 | self.ar_buttons_labels = self.aspect_ratios
257 |
258 | def read_resolutions(self):
259 | res_file = Path(BASE_PATH, "resolutions.txt")
260 | if not res_file.exists():
261 | write_resolutions_file(res_file)
262 |
263 | self.res_labels, res, self.res_comments = parse_resolutions_file("resolutions.txt")
264 | self.res = [list(map(int, r)) for r in res]
265 |
266 | def title(self):
267 | return "Aspect Ratio picker"
268 |
269 | def show(self, is_img2img):
270 | return scripts.AlwaysVisible
271 |
272 | def ui(self, is_img2img):
273 | self.LOCK_OPEN_ICON = "\U0001F513" # 🔓
274 | self.LOCK_CLOSED_ICON = "\U0001F512" # 🔒
275 | self.LAND_AR_ICON = "\U000025AD" # ▭
276 | self.PORT_AR_ICON = "\U000025AF" # ▯
277 | self.INFO_ICON = "\U00002139" # ℹ
278 | self.INFO_CLOSE_ICON = "\U00002BC5" # ⯅
279 | self.OFFSET_ICON = "\U00002B83" # ⮃
280 | self.ONE_DIM_ICON = "\U00002B85" # ⮅
281 |
282 | # Determine the width and height based on the mode (img2img or txt2img)
283 | if is_img2img:
284 | w = self.i2i_w
285 | h = self.i2i_h
286 | else:
287 | w = self.t2i_w
288 | h = self.t2i_h
289 |
290 | # Average number box initialize without rendering
291 | arc_average = gr.Number(label="Current W/H Avg.", value=0, interactive=False, render=False)
292 |
293 | # Precision input box initialize without rendering
294 | arc_prec = gr.Number(label="Precision (px)", value=64, minimum=4, maximum=128, step=4, precision=0, render=False)
295 |
296 | with gr.Accordion(label="Aspect Ratio and Resolution Buttons", open=True):
297 |
298 | with gr.Column(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_container_aspect_ratio'):
299 |
300 | # Get aspect ratios from file
301 | self.read_aspect_ratios()
302 |
303 | # Top row
304 | with gr.Row(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_row_aspect_ratio'):
305 |
306 | # Lock button
307 | arc_lock = ToolButton(value=self.LOCK_OPEN_ICON, visible=True, variant="secondary", elem_id="arsp__arc_lock_button")
308 | # Lock button click event handling
309 | def toggle_lock(icon, avg, w=512, h=512):
310 | icon = self.LOCK_OPEN_ICON if (img2img_state.is_locked if is_img2img else txt2img_state.is_locked) else self.LOCK_CLOSED_ICON
311 | if is_img2img:
312 | img2img_state.toggle_lock()
313 | else:
314 | txt2img_state.toggle_lock()
315 | if not avg:
316 | avg = avg_from_dims(w, h)
317 | return icon, avg
318 | if is_img2img:
319 | lock_w = self.i2i_w
320 | lock_h = self.i2i_h
321 | else:
322 | lock_w = self.t2i_w
323 | lock_h = self.t2i_h
324 | # Lock button event listener
325 | arc_lock.click(toggle_lock,
326 | inputs = [arc_lock, arc_average, lock_w, lock_h],
327 | outputs = [arc_lock, arc_average],
328 | show_progress = 'hidden')
329 |
330 | # Initialize Aspect Ratio buttons (render=False)
331 | ar_buttons, ar_functions = create_ar_buttons(self.ar_buttons_labels, is_img2img)
332 |
333 | # Switch button
334 | arc_switch = ToolButton(value=self.LAND_AR_ICON, visible=True, variant="secondary", elem_id="arsp__arc_switch_button")
335 | # Switch button click event handling
336 | def toggle_switch(*items, **kwargs):
337 | ar_icons = items[:-1]
338 | sw_icon = items[-1]
339 | if ar_icons == tuple(self.aspect_ratios):
340 | ar_icons = tuple(self.flipped_vals)
341 | else:
342 | ar_icons = tuple(self.aspect_ratios)
343 | sw_icon = self.PORT_AR_ICON if sw_icon == self.LAND_AR_ICON else self.LAND_AR_ICON
344 | if is_img2img:
345 | img2img_state.toggle_switch()
346 | else:
347 | txt2img_state.toggle_switch()
348 | return (*ar_icons, sw_icon)
349 | # Switch button event listener
350 | arc_switch.click(toggle_switch,
351 | inputs = ar_buttons+[arc_switch],
352 | outputs = ar_buttons+[arc_switch])
353 |
354 | # AR buttons render
355 | for button in ar_buttons:
356 | button.render()
357 | # AR buttons click event handling
358 | with contextlib.suppress(AttributeError):
359 | for button in ar_buttons:
360 | # AR buttons event listener
361 | button.click(ar_functions[button],
362 | inputs = [arc_average, arc_prec, w, h],
363 | outputs = [arc_average, w, h],
364 | show_progress = 'hidden')
365 |
366 | # Get static resolutions from file
367 | self.read_resolutions()
368 |
369 | # Bottom row
370 | with gr.Row(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_row_resolutions'):
371 |
372 | # Info button to toggle info window
373 | arc_show_info = ToolButton(value=self.INFO_ICON, visible=True, variant="secondary", elem_id="arsp__arc_show_info_button")
374 | arc_hide_info = ToolButton(value=self.INFO_CLOSE_ICON, visible=False, variant="secondary", elem_id="arsp__arc_hide_info_button")
375 | ### Click event handling for info window ###
376 | ##### is defined after everything else #####
377 |
378 | # Mode button
379 | arc_mode = ToolButton(value=self.OFFSET_ICON, visible=True, variant="secondary", elem_id="arsp__arc_mode_button")
380 | # Mode button click event handling
381 | def toggle_mode(icon):
382 | icon = self.ONE_DIM_ICON if icon == self.OFFSET_ICON else self.OFFSET_ICON
383 | if is_img2img:
384 | img2img_state.toggle_mode()
385 | else:
386 | txt2img_state.toggle_mode()
387 | return icon
388 | # Mode button event listener
389 | arc_mode.click(toggle_mode,
390 | inputs = [arc_mode],
391 | outputs = [arc_mode])
392 |
393 | # Static res buttons
394 | buttons, set_res_functions = create_res_buttons(zip(self.res, self.res_labels), is_img2img)
395 |
396 | # Set up click event listeners for the buttons
397 | with contextlib.suppress(AttributeError):
398 | for button in buttons:
399 | button.click(set_res_functions[button],
400 | inputs = [arc_average],
401 | outputs = [arc_average, w, h],
402 | show_progress = 'hidden')
403 |
404 | # Write button_titles.js with labels and comments read from aspect ratios and resolutions files
405 | button_titles = [self.aspect_ratios + self.res_labels]
406 | button_titles.append(self.aspect_ratio_comments + self.res_comments)
407 | write_js_titles_file(button_titles)
408 |
409 | # Information panel
410 | with gr.Column(visible=False, variant="panel", elem_id="arsp__arc_panel") as arc_panel:
411 | with gr.Row():
412 | with gr.Column(scale=2, min_width=100):
413 |
414 | # Average number box render
415 | arc_average.render()
416 |
417 | # Precision input box render
418 | arc_prec.render()
419 |
420 | # Information blurb
421 | gr.Column(scale=1, min_width=10)
422 | with gr.Column(scale=12):
423 | arc_title_heading = gr.Markdown(value=
424 | '''
425 | ### AR and Static Res buttons can be customized in the 'aspect_ratios.txt' and 'resolutions.txt' files
426 | **Aspect Ratio buttons (Top Row)**:
427 | (1) Averages the current width/height in the UI; (2) Offsets to the exact aspect ratio; (3) Rounds to precision.
428 |
429 | **Static Resolution buttons (Bottom Row)**:
430 | Recommended to use 1:1 values for these, to serve as a start point before clicking AR buttons.
431 |
432 | **64px Precision is recommended, the same rounding applied for image "bucketing" when model training.**
433 | '''
434 | )
435 |
436 | # Info panel event listeners
437 | arc_show_info.click(
438 | lambda: [
439 | gr.update(visible=True),
440 | gr.update(visible=False),
441 | gr.update(visible=True),
442 | ],
443 | None,
444 | [
445 | arc_panel,
446 | arc_show_info,
447 | arc_hide_info,
448 | ],
449 | )
450 | arc_hide_info.click(
451 | lambda: [
452 | gr.update(visible=False),
453 | gr.update(visible=True),
454 | gr.update(visible=False),
455 | ],
456 | None,
457 | [arc_panel, arc_show_info, arc_hide_info],
458 | )
459 |
460 | ## Function to update the values in appropriate Width/Height fields
461 | # https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/7456#issuecomment-1414465888
462 | def after_component(self, component, **kwargs):
463 | if kwargs.get("elem_id") == "txt2img_width":
464 | self.t2i_w = component
465 | if kwargs.get("elem_id") == "txt2img_height":
466 | self.t2i_h = component
467 | if kwargs.get("elem_id") == "img2img_width":
468 | self.i2i_w = component
469 | if kwargs.get("elem_id") == "img2img_height":
470 | self.i2i_h = component
471 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | #arsp__txt2img_container_aspect_ratio,
2 | #arsp__img2img_container_aspect_ratio {
3 | gap: 5px !important;
4 | margin-top: 3px;
5 | margin-bottom: 3px;
6 | }
7 |
8 | #arsp__txt2img_row_aspect_ratio,
9 | #arsp__txt2img_row_resolutions,
10 | #arsp__img2img_row_aspect_ratio,
11 | #arsp__img2img_row_resolutions {
12 | gap: 8px;
13 | }
14 |
15 | #arsp__txt2img_row_aspect_ratio button,
16 | #arsp__txt2img_row_resolutions button,
17 | #arsp__img2img_row_aspect_ratio button,
18 | #arsp__img2img_row_resolutions button {
19 | gap: 10px !important;
20 | max-width: unset !important;
21 | }
22 |
23 | button#arsp__arc_lock_button,
24 | button#arsp__arc_mode_button,
25 | button#arsp__arc_switch_button,
26 | button#arsp__arc_show_info_button,
27 | button#arsp__arc_hide_info_button {
28 | max-width: 40px !important;
29 | min-width: unset !important;
30 | padding: var(--size-0-5) var(--size-2) !important;
31 | }
32 |
33 | /* TODO: Use gradio instead if posible */
34 | #arsp__arc_ar_display_text {
35 | height: 22px;
36 | overflow: hidden !important;
37 | }
38 |
39 | /* Fix for Lobe theme */
40 | /* https://github.com/canisminor1990/sd-webui-lobe-theme/blob/d4c4a48e8025d32b202716d4ab8d806580752256/src/styles/components/button.ts */
41 | .hide.svelte-1ipelgc {
42 | display: none !important;
43 | }
44 | .primary.svelte-1ipelgc {
45 | background: var(--button-primary-background-fill) !important;
46 | }
47 | .secondary.svelte-1ipelgc {
48 | background: var(--button-secondary-background-fill) !important;
49 | }
50 |
--------------------------------------------------------------------------------