Files
Tropfchen-ComfyUI-yaResolut…/nodes.py
T
2023-09-22 23:39:42 +02:00

242 lines
6.8 KiB
Python

import re
class Dimensions:
def __init__(self, width: int, height: int):
self.width = width
self.height = height
@property
def width(self):
return self._width
@width.setter
def width(self, value: int):
if value < 64:
raise ValueError("width of less than 64 pixel")
self._width = int(value / 2) * 2 if value % 2 else value
@property
def height(self):
return self._height
@height.setter
def height(self, value: int):
if value < 64:
raise ValueError("height of less than 64 pixel")
self._height = int(value / 2) * 2 if value % 2 else value
def calculate_aspect_ratio(
base_resolution: int, ratio: float, overextend: bool
) -> Dimensions:
width = base_resolution
height = base_resolution
if overextend:
if ratio > 1:
height *= ratio
else:
width /= ratio
else:
if ratio > 1:
width /= ratio
else:
height *= ratio
return Dimensions(int(width), int(height))
def calculate_constant_constant_resolution(
base_resolution: int, ratio: float
) -> Dimensions:
pixel_count = base_resolution ** 2
new_height = (pixel_count * ratio) ** 0.5
new_width = new_height / ratio
return Dimensions(new_width, new_height)
class YARS:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
ratios = [
"1:1",
"landscape (4:3)",
"landscape (3:2)",
"landscape (16:9)",
"landscape (16:10)",
"landscape (21:9)",
"portrait (3:4)",
"portrait (2:3)",
"portrait (9:16)",
"portrait (9:10)",
"portrait (9:21)",
]
return {
"required": {
"base_resolution": (
"INT",
{
"default": 512,
"min": 512,
"max": 8192,
"step": 128,
},
),
"aspect_ratio": ((ratios),),
"overextend": (
"BOOLEAN",
{"default": False, "label_on": "yes ", "label_off": "no "},
),
},
}
RETURN_TYPES = ("INT", "INT")
RETURN_NAMES = ("width", "height")
FUNCTION = "calculate"
OUTPUT_NODE = False
CATEGORY = "utils"
def calculate(
self,
base_resolution: int,
aspect_ratio: str,
overextend: bool,
) -> tuple[int, int]:
if m := re.search(r"(\d+):(\d+)", aspect_ratio):
ratio: float = int(m.group(2)) / int(m.group(1))
d = calculate_aspect_ratio(base_resolution, ratio, overextend)
return (d.width, d.height)
raise ValueError(f"Could't find aspect ratio in string `{aspect_ratio}`")
class YARSAdv:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"base_resolution": (
"INT",
{
"default": 512,
"min": 512,
"max": 8192,
"step": 128,
},
),
"width_ratio": (
"INT",
{
"default": 1,
"min": 1,
"max": 1024,
"step": 1,
},
),
"height_ratio": (
"INT",
{
"default": 1,
"min": 1,
"max": 1024,
"step": 1,
},
),
"overextend": (
"BOOLEAN",
{"default": False, "label_on": "yes ", "label_off": "no "},
),
"constant_resolution": (
"BOOLEAN",
{"default": False, "label_on": "yes ", "label_off": "no "},
),
},
}
RETURN_TYPES = ("INT", "INT")
RETURN_NAMES = ("width", "height")
FUNCTION = "calculate"
OUTPUT_NODE = False
CATEGORY = "utils"
def calculate(
self,
base_resolution: int,
width_ratio: int,
height_ratio: int,
overextend: bool,
constant_resolution: bool,
) -> tuple[int, int]:
ratio: float = height_ratio / width_ratio
if constant_resolution:
d = calculate_constant_constant_resolution(base_resolution, ratio)
else:
d = calculate_aspect_ratio(base_resolution, ratio, overextend)
return (d.width, d.height)
NODE_CLASS_MAPPINGS = {"YARS": YARS, "YARSAdv": YARSAdv}
NODE_DISPLAY_NAME_MAPPINGS = {
"YARS": "yaResolution Selector",
"YARSAdv": "yaResolution Selector (Advanced)",
}
if __name__ == "__main__":
import unittest
class TestDimensions(unittest.TestCase):
def test_constant_resolution_calculates_correct_dimensions(self):
d = calculate_constant_constant_resolution(1024, 1)
self.assertEqual((d.width, d.height), (1024, 1024), "Incorrect dimensions")
def test_constant_resolution_calculates_correct_aspect_ratio(self):
d = calculate_constant_constant_resolution(1024, 4 / 3)
self.assertAlmostEqual(
d.height / d.width, 4 / 3, 2, "Incorrect aspect ratio"
)
def test_constant_resolution_calculates_correct_pixel_count(self):
d = calculate_constant_constant_resolution(1024, 4 / 3)
self.assertEqual(d.width * d.height, 1047252, "Incorrect pixel count")
def test_calculate_dimensions_with_false_overextend(self):
d = calculate_aspect_ratio(1024, 4 / 3, False)
self.assertEqual(
(d.width, d.height),
(768, 1024),
"Incorrect dimensions without overextending",
)
def test_calculate_dimensions_with_true_overextend(self):
d = calculate_aspect_ratio(512, 4 / 3, True)
self.assertEqual(
(d.width, d.height),
(512, 682),
"Incorrect dimensions with overextending",
)
def test_cleanup_dimensions_raises_error_with_low_height(self):
with self.assertRaises(
ValueError, msg="No error raised with height less than 64 pixels"
):
Dimensions(512, 60)
def test_cleanup_dimensions_raises_error_with_low_width(self):
with self.assertRaises(
ValueError, msg="No error raised with width less than 64 pixels"
):
Dimensions(55, 512)
unittest.main()