| from abc import ABC, abstractmethod |
| from typing import Any, Mapping, Sequence, Tuple |
|
|
|
|
| SDXL_SUPPORTED_RESOLUTIONS = [ |
| (1024, 1024, 1.0), |
| (1152, 896, 1.2857142857142858), |
| (896, 1152, 0.7777777777777778), |
| (1216, 832, 1.4615384615384615), |
| (832, 1216, 0.6842105263157895), |
| (1344, 768, 1.75), |
| (768, 1344, 0.5714285714285714), |
| (1536, 640, 2.4), |
| (640, 1536, 0.4166666666666667), |
| ] |
|
|
| SDXL_EXTENDED_RESOLUTIONS = [ |
| (512, 2048, 0.25), |
| (512, 1984, 0.26), |
| (512, 1920, 0.27), |
| (512, 1856, 0.28), |
| (576, 1792, 0.32), |
| (576, 1728, 0.33), |
| (576, 1664, 0.35), |
| (640, 1600, 0.4), |
| (640, 1536, 0.42), |
| (704, 1472, 0.48), |
| (704, 1408, 0.5), |
| (704, 1344, 0.52), |
| (768, 1344, 0.57), |
| (768, 1280, 0.6), |
| (832, 1216, 0.68), |
| (832, 1152, 0.72), |
| (896, 1152, 0.78), |
| (896, 1088, 0.82), |
| (960, 1088, 0.88), |
| (960, 1024, 0.94), |
| (1024, 1024, 1.0), |
| (1024, 960, 1.8), |
| (1088, 960, 1.14), |
| (1088, 896, 1.22), |
| (1152, 896, 1.30), |
| (1152, 832, 1.39), |
| (1216, 832, 1.47), |
| (1280, 768, 1.68), |
| (1344, 768, 1.76), |
| (1408, 704, 2.0), |
| (1472, 704, 2.10), |
| (1536, 640, 2.4), |
| (1600, 640, 2.5), |
| (1664, 576, 2.90), |
| (1728, 576, 3.0), |
| (1792, 576, 3.12), |
| (1856, 512, 3.63), |
| (1920, 512, 3.76), |
| (1984, 512, 3.89), |
| (2048, 512, 4.0), |
| ] |
|
|
|
|
| class Resolution(ABC): |
| @classmethod |
| @abstractmethod |
| def resolutions(cls) -> Sequence[Tuple[int, int, float]]: ... |
|
|
| @classmethod |
| def INPUT_TYPES(cls) -> Mapping[str, Any]: |
| return { |
| "required": { |
| "resolution": ([f"{res[0]}x{res[1]}" for res in cls.resolutions()],) |
| } |
| } |
|
|
| RETURN_TYPES = ("INT", "INT") |
| RETURN_NAMES = ("width", "height") |
| FUNCTION = "op" |
| CATEGORY = "math/graphics" |
|
|
| def op(self, resolution: str) -> tuple[int, int]: |
| width, height = resolution.split("x") |
| return (int(width), int(height)) |
|
|
|
|
| class NearestResolution(ABC): |
| @classmethod |
| @abstractmethod |
| def resolutions(cls) -> Sequence[Tuple[int, int, float]]: ... |
|
|
| @classmethod |
| def INPUT_TYPES(cls) -> Mapping[str, Any]: |
| return {"required": {"image": ("IMAGE",)}} |
|
|
| RETURN_TYPES = ("INT", "INT") |
| RETURN_NAMES = ("width", "height") |
| FUNCTION = "op" |
| CATEGORY = "math/graphics" |
|
|
| def op(self, image) -> tuple[int, int]: |
| image_width = image.size()[2] |
| image_height = image.size()[1] |
| print(f"Input image resolution: {image_width}x{image_height}") |
| image_ratio = image_width / image_height |
| differences = [ |
| (abs(image_ratio - resolution[2]), resolution) |
| for resolution in self.resolutions() |
| ] |
| smallest = None |
| for difference in differences: |
| if smallest is None: |
| smallest = difference |
| else: |
| if difference[0] < smallest[0]: |
| smallest = difference |
| if smallest is not None: |
| width = smallest[1][0] |
| height = smallest[1][1] |
| else: |
| width = 1024 |
| height = 1024 |
| print(f"Selected resolution: {width}x{height}") |
| return (width, height) |
|
|
|
|
| class SDXLResolution(Resolution): |
| @classmethod |
| def resolutions(cls): |
| return SDXL_SUPPORTED_RESOLUTIONS |
|
|
|
|
| class SDXLExtendedResolution(Resolution): |
| @classmethod |
| def resolutions(cls): |
| return SDXL_EXTENDED_RESOLUTIONS |
|
|
|
|
| class NearestSDXLResolution(NearestResolution): |
| @classmethod |
| def resolutions(cls): |
| return SDXL_SUPPORTED_RESOLUTIONS |
|
|
|
|
| class NearestSDXLExtendedResolution(NearestResolution): |
| @classmethod |
| def resolutions(cls): |
| return SDXL_EXTENDED_RESOLUTIONS |
|
|
|
|
| NODE_CLASS_MAPPINGS = { |
| "CM_SDXLResolution": SDXLResolution, |
| "CM_NearestSDXLResolution": NearestSDXLResolution, |
| "CM_SDXLExtendedResolution": SDXLExtendedResolution, |
| "CM_NearestSDXLExtendedResolution": NearestSDXLExtendedResolution, |
| } |
|
|