mirror of
https://github.com/thomasasfk/sd-webui-aspect-ratio-helper.git
synced 2026-01-26 19:19:58 +00:00
Add aspect ratios configuration option (#15)
* Add aspect ratios configuration option - Add new component for configurable aspect ratios - Add options allowing for aspect ratios to use max option - Update documentation to reflect aspect ratio functionality - Refactor options to include in each relevant component
This commit is contained in:
58
README.md
58
README.md
@@ -4,50 +4,64 @@ Simple extension to easily maintain aspect ratio while changing dimensions.
|
||||
|
||||
Install via the extensions tab on the [AUTOMATIC1111 webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui).
|
||||
|
||||
## Main features:
|
||||
## Features
|
||||
|
||||
- Scale to maximum width or height
|
||||
- Upon clicking, the dimensions will scale according to the configured maximum value
|
||||
- Scale to maximum dimension
|
||||
- Upon clicking, the width and height will scale according to the configured maximum value
|
||||
- Aspect ratio will be retained, the smaller or equivalent dimension will be scaled to match
|
||||
- Scale to aspect ratio
|
||||
- Upon clicking, the current dimensions will be scaled to the given aspect ratio, using the highest width or height
|
||||
- i.e `4:3 of 256x512 = 512x384` `9:16 of 512x256 = 288x512` `1:1 of 256x300 = 300x300`
|
||||
- You can optionally toggle this to use the "Maximum dimension" slider value
|
||||
- i.e `4:3 of 512 = 512x384` `9:16 of 512 = 288x512` `1:1 of 300 = 300x300`
|
||||
- Scale by percentage
|
||||
- Upon clicking, the current dimensions will be multiplied by the given percentage, with aspect ratio maintained
|
||||
- i.e `150% of 512x512 = 768x768` `75% of 512x256 = 384x192` etc.
|
||||
- i.e `-25% of 512x256 = 384x192` `+50% of 512x512 = 768x768`
|
||||
- You can also change the display of these if you find it more intuitive
|
||||
- i.e `75% of 512x256 = 384x192` `150% of 512x512 = 768x768`
|
||||
- i.e `x0.75 of 512x256 = 384x192` `x1.5 of 512x512 = 768x768`
|
||||
|
||||

|
||||
|
||||
## Settings:
|
||||
## Settings
|
||||
|
||||
- Expand by default
|
||||
- Expand by default (`False`)
|
||||
- Determines whether the 'Aspect Ratio Helper' accordion expands by default
|
||||
- Show maximum width or height button
|
||||
- Maximum width or height default
|
||||
- Show predefined percentage buttons
|
||||
- Predefined percentage buttons
|
||||
- Comma separated list of percentages
|
||||
- i.e `25, 50, 75, 125, 150, 175, 200` `50, 125, 300` etc.
|
||||
- Predefined percentage display format
|
||||
- UI Component order (`MaxDimensionScaler, PredefinedAspectRatioButtons, PredefinedPercentageButtons`)
|
||||
- Determines the order in which the UI components will render
|
||||
- Show maximum dimension button (`True`)
|
||||
- Maximum dimension default (`1024`)
|
||||
- Show pre-defined aspect ratio buttons (`True`)
|
||||
- Use "Maximum dimension" for aspect ratio buttons (`False`)
|
||||
- Pre-defined aspect ratio buttons (`1:1, 4:3, 16:9, 9:16, 21:9`)
|
||||
- i.e `1:1, 4:3, 16:9, 9:16, 21:9` `2:3, 1:5, 3:5`
|
||||
- Show pre-defined percentage buttons (`True`)
|
||||
- Pre-defined percentage buttons (`25, 50, 75, 125, 150, 175, 200`)
|
||||
- i.e `25, 50, 75, 125, 150, 175, 200` `50, 125, 300`
|
||||
- Pre-defined percentage display format (`Incremental/decremental percentage (-50%, +50%)`)
|
||||
- `Incremental/decremental percentage (-50%, +50%)`
|
||||
- `Raw percentage (50%, 150%)`
|
||||
- `Multiplication (x0.5, x1.5)`
|
||||
|
||||

|
||||
|
||||
## Contributing:
|
||||
## Contributing
|
||||
|
||||
- Open to suggestions
|
||||
- Pull requests are appreciated
|
||||
- Write tests if possible and useful
|
||||
- Run pre-commit
|
||||
- Open an issue for suggestions
|
||||
- Raise a pull request
|
||||
|
||||
## Dependencies:
|
||||
## Dependencies
|
||||
|
||||
Developed using existing [AUTOMATIC1111 webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) dependencies.
|
||||
|
||||
However - for running unit tests, we use pytest:
|
||||
However - for running unit tests, we use pytest.
|
||||
|
||||
```bash
|
||||
pip install pytest
|
||||
```
|
||||
|
||||
## Testing:
|
||||
From the root of the repository run:
|
||||
## Testing
|
||||
From the root of the repository.
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
|
||||
@@ -21,23 +21,53 @@ class ArhUIComponent(ABC):
|
||||
@abstractmethod
|
||||
def should_show() -> bool: ...
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def add_options(): ...
|
||||
|
||||
|
||||
class MaxDimensionScaler(ArhUIComponent):
|
||||
|
||||
def render(self):
|
||||
max_dim_default = _settings.safe_opt(
|
||||
_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
)
|
||||
self.script.max_dimension = float(max_dim_default)
|
||||
|
||||
inputs = outputs = [self.script.wc, self.script.hc]
|
||||
with gr.Row():
|
||||
max_dimension = gr.inputs.Slider(
|
||||
|
||||
with gr.Row(
|
||||
visible=self.should_show(),
|
||||
):
|
||||
max_dim_default = _settings.safe_opt(
|
||||
_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
)
|
||||
# todo: when using gr.Slider (not deprecated), the default value
|
||||
# is somehow always 270?... can't figure out why.
|
||||
# using legacy inputs.Slider for now as it doesn't have the issue.
|
||||
max_dimension_slider = gr.inputs.Slider(
|
||||
minimum=_constants.MIN_DIMENSION,
|
||||
maximum=_constants.MAX_DIMENSION,
|
||||
step=1,
|
||||
default=_settings.safe_opt(
|
||||
_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
),
|
||||
label='Maximum width or height (whichever is higher)',
|
||||
default=max_dim_default,
|
||||
label='Maximum dimension',
|
||||
)
|
||||
gr.Button(value='Scale to maximum width or height').click(
|
||||
fn=_util.scale_dimensions_to,
|
||||
inputs=[*inputs, max_dimension],
|
||||
|
||||
def _update_max_dimension(_max_dimension):
|
||||
self.script.max_dimension = _max_dimension
|
||||
|
||||
max_dimension_slider.change(
|
||||
_update_max_dimension,
|
||||
inputs=[max_dimension_slider],
|
||||
show_progress=False,
|
||||
)
|
||||
|
||||
gr.Button(
|
||||
value='Scale to maximum dimension',
|
||||
visible=self.should_show(),
|
||||
).click(
|
||||
fn=_util.scale_dimensions_to_max_dim,
|
||||
inputs=[*inputs, max_dimension_slider],
|
||||
outputs=outputs,
|
||||
)
|
||||
|
||||
@@ -45,17 +75,145 @@ class MaxDimensionScaler(ArhUIComponent):
|
||||
def should_show() -> bool:
|
||||
return _settings.safe_opt(_constants.ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY)
|
||||
|
||||
@staticmethod
|
||||
def add_options(shared):
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
),
|
||||
label='Show maximum dimension button',
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
),
|
||||
label='Maximum dimension default',
|
||||
component=gr.Slider,
|
||||
component_args={
|
||||
'minimum': _constants.MIN_DIMENSION,
|
||||
'maximum': _constants.MAX_DIMENSION,
|
||||
'step': 1,
|
||||
},
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class PredefinedAspectRatioButtons(ArhUIComponent):
|
||||
|
||||
def render(self):
|
||||
use_max_dim_op = _settings.safe_opt(
|
||||
_constants.ARH_PREDEFINED_ASPECT_RATIO_USE_MAX_DIM_KEY,
|
||||
)
|
||||
aspect_ratios = _settings.safe_opt(
|
||||
_constants.ARH_PREDEFINED_ASPECT_RATIOS_KEY,
|
||||
).split(',')
|
||||
|
||||
with gr.Column(
|
||||
variant='panel',
|
||||
visible=self.should_show(),
|
||||
), gr.Row(
|
||||
variant='compact',
|
||||
visible=self.should_show(),
|
||||
):
|
||||
for ar_str in aspect_ratios:
|
||||
w, h, *_ = [abs(float(d)) for d in ar_str.split(':')]
|
||||
|
||||
inputs = []
|
||||
if use_max_dim_op:
|
||||
ar_func = partial(
|
||||
_util.scale_dimensions_to_max_dim_func,
|
||||
width=w, height=h,
|
||||
max_dim=lambda: self.script.max_dimension,
|
||||
)
|
||||
else:
|
||||
inputs.extend([self.script.wc, self.script.hc])
|
||||
ar_func = partial(
|
||||
_util.scale_dimensions_to_ui_width_or_height,
|
||||
arw=w, arh=h,
|
||||
)
|
||||
|
||||
gr.Button(
|
||||
value=self.display_func(ar_str) or ar_str,
|
||||
visible=self.should_show(),
|
||||
).click(
|
||||
fn=ar_func,
|
||||
inputs=inputs,
|
||||
outputs=[self.script.wc, self.script.hc],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def should_show() -> bool:
|
||||
return _settings.safe_opt(
|
||||
_constants.ARH_SHOW_PREDEFINED_ASPECT_RATIOS_KEY,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_options(shared):
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_SHOW_PREDEFINED_ASPECT_RATIOS_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_SHOW_PREDEFINED_ASPECT_RATIOS_KEY,
|
||||
),
|
||||
label='Show pre-defined aspect ratio buttons',
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_PREDEFINED_ASPECT_RATIO_USE_MAX_DIM_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_PREDEFINED_ASPECT_RATIO_USE_MAX_DIM_KEY,
|
||||
),
|
||||
label='Use "Maximum dimension" for aspect ratio buttons (by '
|
||||
'default we use the max width or height)',
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_PREDEFINED_ASPECT_RATIOS_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_PREDEFINED_ASPECT_RATIOS_KEY,
|
||||
),
|
||||
label='Pre-defined aspect ratio buttons '
|
||||
'(1:1, 4:3, 16:9, 9:16, 21:9)',
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
|
||||
@property
|
||||
def display_func(self) -> callable:
|
||||
return lambda _: None # todo: different displays for aspect ratios.
|
||||
|
||||
|
||||
class PredefinedPercentageButtons(ArhUIComponent):
|
||||
|
||||
def render(self):
|
||||
inputs = outputs = [self.script.wc, self.script.hc]
|
||||
with gr.Column(variant='panel'), gr.Row(variant='compact'):
|
||||
with gr.Column(
|
||||
variant='panel',
|
||||
visible=self.should_show(),
|
||||
), gr.Row(
|
||||
variant='compact',
|
||||
visible=self.should_show(),
|
||||
):
|
||||
pps = _settings.safe_opt(_constants.ARH_PREDEFINED_PERCENTAGES_KEY)
|
||||
percentages = [abs(int(x)) for x in pps.split(',')]
|
||||
|
||||
for percentage in percentages:
|
||||
display = self.display_func(percentage)
|
||||
gr.Button(value=display).click(
|
||||
gr.Button(
|
||||
value=display,
|
||||
visible=self.should_show(),
|
||||
).click(
|
||||
fn=partial(
|
||||
_util.scale_by_percentage,
|
||||
pct=percentage / 100,
|
||||
@@ -70,6 +228,45 @@ class PredefinedPercentageButtons(ArhUIComponent):
|
||||
_constants.ARH_SHOW_PREDEFINED_PERCENTAGES_KEY,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_options(shared):
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_SHOW_PREDEFINED_PERCENTAGES_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_SHOW_PREDEFINED_PERCENTAGES_KEY,
|
||||
),
|
||||
label='Show pre-defined percentage buttons',
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_PREDEFINED_PERCENTAGES_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_PREDEFINED_PERCENTAGES_KEY,
|
||||
),
|
||||
label='Pre-defined percentage buttons (75, 125, 150)',
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_PREDEFINED_PERCENTAGES_DISPLAY_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=_settings.OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_PREDEFINED_PERCENTAGES_DISPLAY_KEY,
|
||||
),
|
||||
label='Pre-defined percentage display format',
|
||||
component=gr.Dropdown,
|
||||
component_args=lambda: {
|
||||
'choices': tuple(
|
||||
_settings.PREDEFINED_PERCENTAGES_DISPLAY_MAP.keys(),
|
||||
),
|
||||
},
|
||||
section=_constants.SECTION,
|
||||
),
|
||||
)
|
||||
|
||||
@property
|
||||
def display_func(self) -> callable:
|
||||
return _settings.PREDEFINED_PERCENTAGES_DISPLAY_MAP.get(
|
||||
|
||||
@@ -9,7 +9,12 @@ ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY = 'arh_show_max_width_or_height'
|
||||
ARH_MAX_WIDTH_OR_HEIGHT_KEY = 'arh_max_width_or_height'
|
||||
ARH_SHOW_PREDEFINED_PERCENTAGES_KEY = 'arh_show_predefined_percentages'
|
||||
ARH_PREDEFINED_PERCENTAGES_KEY = 'arh_predefined_percentages'
|
||||
ARH_SHOW_PREDEFINED_ASPECT_RATIOS_KEY = 'arh_show_predefined_aspect_ratios'
|
||||
ARH_PREDEFINED_ASPECT_RATIOS_KEY = 'arh_predefined_aspect_ratios'
|
||||
ARH_PREDEFINED_ASPECT_RATIO_USE_MAX_DIM_KEY \
|
||||
= 'arh_predefined_aspect_ratio_use_max_dim'
|
||||
ARH_PREDEFINED_PERCENTAGES_DISPLAY_KEY \
|
||||
= 'arh_predefined_percentages_display_key'
|
||||
DEFAULT_PERCENTAGES_DISPLAY_KEY \
|
||||
= 'Incremental/decremental percentage (-50%, +50%)'
|
||||
SECTION = 'aspect_ratio_helper', EXTENSION_NAME
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import itertools
|
||||
|
||||
import gradio as gr
|
||||
from modules import shared
|
||||
|
||||
@@ -11,13 +13,15 @@ PREDEFINED_PERCENTAGES_DISPLAY_MAP = {
|
||||
'Multiplication (x0.5, x1.5)': _util.display_multiplication,
|
||||
}
|
||||
|
||||
ELEMENTS = (
|
||||
COMPONENTS = (
|
||||
_components.MaxDimensionScaler,
|
||||
_components.PredefinedAspectRatioButtons,
|
||||
_components.PredefinedPercentageButtons,
|
||||
)
|
||||
|
||||
DEFAULT_UI_COMPONENT_ORDER_KEY_LIST = [e.__name__ for e in COMPONENTS]
|
||||
DEFAULT_UI_COMPONENT_ORDER_KEY = ', '.join(
|
||||
[e.__name__ for e in ELEMENTS], # noqa
|
||||
DEFAULT_UI_COMPONENT_ORDER_KEY_LIST,
|
||||
)
|
||||
OPT_KEY_TO_DEFAULT_MAP = {
|
||||
_constants.ARH_EXPAND_BY_DEFAULT_KEY: False,
|
||||
@@ -31,6 +35,10 @@ OPT_KEY_TO_DEFAULT_MAP = {
|
||||
'25, 50, 75, 125, 150, 175, 200',
|
||||
_constants.ARH_PREDEFINED_PERCENTAGES_DISPLAY_KEY:
|
||||
_constants.DEFAULT_PERCENTAGES_DISPLAY_KEY,
|
||||
_constants.ARH_SHOW_PREDEFINED_ASPECT_RATIOS_KEY: True,
|
||||
_constants.ARH_PREDEFINED_ASPECT_RATIO_USE_MAX_DIM_KEY: False,
|
||||
_constants.ARH_PREDEFINED_ASPECT_RATIOS_KEY:
|
||||
'1:1, 4:3, 16:9, 9:16, 21:9',
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +46,20 @@ def safe_opt(key):
|
||||
return _util.safe_opt_util(shared.opts, key, OPT_KEY_TO_DEFAULT_MAP)
|
||||
|
||||
|
||||
def sort_elements_by_keys(
|
||||
elements: list[_components.ArhUIComponent],
|
||||
def sort_components_by_keys(
|
||||
components: list[_components.ArhUIComponent],
|
||||
) -> list[_components.ArhUIComponent]:
|
||||
ordered_component_keys = safe_opt(
|
||||
_constants.ARH_UI_COMPONENT_ORDER_KEY,
|
||||
).split(',')
|
||||
|
||||
# this can happen if we add new components, but the user has old settings.
|
||||
# if this happens, we find the missing components, and append them.
|
||||
if len(ordered_component_keys) != len(COMPONENTS):
|
||||
all_components = set(DEFAULT_UI_COMPONENT_ORDER_KEY_LIST)
|
||||
missing_components = all_components - set(ordered_component_keys)
|
||||
ordered_component_keys.extend(missing_components)
|
||||
|
||||
try:
|
||||
component_key_to_order_dict = {
|
||||
key: order for order, key in enumerate(
|
||||
@@ -51,7 +67,7 @@ def sort_elements_by_keys(
|
||||
)
|
||||
}
|
||||
return sorted(
|
||||
elements,
|
||||
components,
|
||||
key=lambda c: component_key_to_order_dict.get(
|
||||
c.__class__.__name__,
|
||||
),
|
||||
@@ -63,11 +79,13 @@ def sort_elements_by_keys(
|
||||
f'the intended syntax for the setting, i.e '
|
||||
f'"{DEFAULT_UI_COMPONENT_ORDER_KEY}"',
|
||||
)
|
||||
return elements
|
||||
return components
|
||||
|
||||
|
||||
def on_ui_settings():
|
||||
section = 'aspect_ratio_helper', _constants.EXTENSION_NAME
|
||||
|
||||
# default ui options
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_EXPAND_BY_DEFAULT_KEY,
|
||||
info=shared.OptionInfo(
|
||||
@@ -85,80 +103,17 @@ def on_ui_settings():
|
||||
_constants.ARH_UI_COMPONENT_ORDER_KEY,
|
||||
),
|
||||
label='UI Component order',
|
||||
# todo: temporary drop-down to avoid user error!
|
||||
# we only have two components so 2 possible orders.
|
||||
# however, this will exponentially grow with more components.
|
||||
# if that happens, permutations is impractical, revisit then.
|
||||
component=gr.Dropdown,
|
||||
component_args=lambda: {
|
||||
'choices': (
|
||||
DEFAULT_UI_COMPONENT_ORDER_KEY,
|
||||
', '.join(
|
||||
DEFAULT_UI_COMPONENT_ORDER_KEY.split(',')[::-1],
|
||||
),
|
||||
),
|
||||
},
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
),
|
||||
label='Show maximum width or height button',
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY,
|
||||
),
|
||||
label='Maximum width or height default',
|
||||
component=gr.Slider,
|
||||
component_args={
|
||||
'minimum': _constants.MIN_DIMENSION,
|
||||
'maximum': _constants.MAX_DIMENSION,
|
||||
'step': 1,
|
||||
},
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_SHOW_PREDEFINED_PERCENTAGES_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_SHOW_PREDEFINED_PERCENTAGES_KEY,
|
||||
),
|
||||
label='Show predefined percentage buttons',
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_PREDEFINED_PERCENTAGES_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_PREDEFINED_PERCENTAGES_KEY,
|
||||
),
|
||||
label='Predefined percentage buttons, applied to dimensions (75, '
|
||||
'125, 150)',
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
key=_constants.ARH_PREDEFINED_PERCENTAGES_DISPLAY_KEY,
|
||||
info=shared.OptionInfo(
|
||||
default=OPT_KEY_TO_DEFAULT_MAP.get(
|
||||
_constants.ARH_PREDEFINED_PERCENTAGES_DISPLAY_KEY,
|
||||
),
|
||||
label='Predefined percentage display format',
|
||||
component=gr.Dropdown,
|
||||
component_args=lambda: {
|
||||
'choices': tuple(PREDEFINED_PERCENTAGES_DISPLAY_MAP.keys()),
|
||||
'choices': [
|
||||
', '.join(p) for p in itertools.permutations(
|
||||
DEFAULT_UI_COMPONENT_ORDER_KEY_LIST,
|
||||
)
|
||||
],
|
||||
},
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
|
||||
for component in COMPONENTS:
|
||||
component.add_options(shared)
|
||||
|
||||
@@ -37,10 +37,28 @@ def scale_by_percentage(width, height, pct) -> tuple[int, int]:
|
||||
return clamp_to_boundaries(new_width, new_height, aspect_ratio)
|
||||
|
||||
|
||||
def scale_dimensions_to(
|
||||
def scale_dimensions_to_ui_width_or_height(
|
||||
width, height, arw, arh,
|
||||
) -> tuple[int, int]:
|
||||
return scale_dimensions_to_max_dim(arw, arh, max(width, height))
|
||||
|
||||
|
||||
def scale_dimensions_to_max_dim_func(
|
||||
width, height, max_dim: callable,
|
||||
) -> tuple[int, int]:
|
||||
return scale_dimensions_to_max_dim(width, height, max_dim())
|
||||
|
||||
|
||||
def scale_dimensions_to_max_dim(
|
||||
width, height, max_dim,
|
||||
) -> tuple[int, int]:
|
||||
aspect_ratio = float(width) / float(height)
|
||||
return scale_dimensions_to_ar(width, height, max_dim, aspect_ratio)
|
||||
|
||||
|
||||
def scale_dimensions_to_ar(
|
||||
width, height, max_dim, aspect_ratio,
|
||||
) -> tuple[int, int]:
|
||||
if width > height:
|
||||
new_width = max_dim
|
||||
new_height = int(round(max_dim / aspect_ratio))
|
||||
@@ -63,4 +81,19 @@ def clamp_to_boundaries(width, height, aspect_ratio) -> tuple[int, int]:
|
||||
if height < _const.MIN_DIMENSION:
|
||||
height = _const.MIN_DIMENSION
|
||||
width = int(round(height * aspect_ratio))
|
||||
|
||||
# for insane aspect ratios we don't support... i.e 1:100
|
||||
# 64:6400 when run through this function, so we clamp to 64:2048 (‾◡◝)
|
||||
# also. when the user does this it breaks the "scale to max" function
|
||||
# on the ui until they change to another reasonable aspect ratio.
|
||||
# todo: figure out why ^ and handle it better.
|
||||
if width < _const.MIN_DIMENSION:
|
||||
width = _const.MIN_DIMENSION
|
||||
elif width > _const.MAX_DIMENSION:
|
||||
width = _const.MAX_DIMENSION
|
||||
if height < _const.MIN_DIMENSION:
|
||||
height = _const.MIN_DIMENSION
|
||||
elif height > _const.MAX_DIMENSION:
|
||||
height = _const.MAX_DIMENSION
|
||||
|
||||
return width, height
|
||||
|
||||
@@ -9,12 +9,13 @@ import aspect_ratio_helper._settings as _settings
|
||||
class AspectRatioStepScript(scripts.Script):
|
||||
|
||||
def __init__(self):
|
||||
self.t2i_w = None
|
||||
self.t2i_h = None
|
||||
self.i2i_w = None
|
||||
self.i2i_h = None
|
||||
self.wc = None
|
||||
self.hc = None
|
||||
self.t2i_w: gr.components.Slider | None = None
|
||||
self.t2i_h: gr.components.Slider | None = None
|
||||
self.i2i_w: gr.components.Slider | None = None
|
||||
self.i2i_h: gr.components.Slider | None = None
|
||||
self.wc: gr.components.Slider
|
||||
self.hc: gr.components.Slider
|
||||
self.max_dimension: float
|
||||
|
||||
def title(self) -> str:
|
||||
return _constants.EXTENSION_NAME
|
||||
@@ -26,14 +27,14 @@ class AspectRatioStepScript(scripts.Script):
|
||||
if is_img2img:
|
||||
self.wc, self.hc = self.i2i_w, self.i2i_h
|
||||
else:
|
||||
self.wc, self.hc = self.t2i_h, self.t2i_w
|
||||
self.wc, self.hc = self.t2i_w, self.t2i_h # noqa
|
||||
|
||||
elements = _settings.sort_elements_by_keys(
|
||||
[element(self) for element in _settings.ELEMENTS],
|
||||
components = _settings.sort_components_by_keys(
|
||||
[component(self) for component in _settings.COMPONENTS],
|
||||
)
|
||||
|
||||
if not any(element.should_show() for element in elements):
|
||||
return # no elements should render, so just return.
|
||||
if not any(component.should_show() for component in components):
|
||||
return # no components should render, so just return.
|
||||
|
||||
start_expanded: bool = _settings.safe_opt(
|
||||
_constants.ARH_EXPAND_BY_DEFAULT_KEY,
|
||||
@@ -42,9 +43,11 @@ class AspectRatioStepScript(scripts.Script):
|
||||
_constants.EXTENSION_NAME,
|
||||
open=start_expanded,
|
||||
):
|
||||
for element in elements:
|
||||
if element.should_show():
|
||||
element.render()
|
||||
for component in components:
|
||||
# we deliberately DON'T check component.should_show() here.
|
||||
# we need to call render to instantiate the components, we use
|
||||
# the visible property on each component to hide them.
|
||||
component.render()
|
||||
|
||||
def after_component(self, component: gr.components.Component, **kwargs):
|
||||
element_id = kwargs.get('elem_id')
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 56 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 66 KiB |
@@ -142,10 +142,10 @@ def test_scale_by_percentage(
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_scale_dimensions_to(
|
||||
def test_scale_dimensions_to_max_dim(
|
||||
width, height, max_dim, expected,
|
||||
):
|
||||
assert _util.scale_dimensions_to(
|
||||
assert _util.scale_dimensions_to_max_dim(
|
||||
width, height, max_dim,
|
||||
) == expected
|
||||
|
||||
|
||||
Reference in New Issue
Block a user