From c58a94f6b27372ebd0881232dbc351d55ceaaeec Mon Sep 17 00:00:00 2001 From: jammyfu Date: Tue, 24 Dec 2024 19:21:06 +0800 Subject: [PATCH] add image resolution --- __init__.py | 8 +- __pycache__/__init__.cpython-311.pyc | Bin 829 -> 995 bytes .../dynamic_image_input.cpython-311.pyc | Bin 1638 -> 2186 bytes .../image_resolution_adjuster.cpython-311.pyc | Bin 0 -> 11046 bytes .../image_scale_calculator.cpython-311.pyc | Bin 9143 -> 9178 bytes .../remove_empty_lines.cpython-311.pyc | Bin 3621 -> 3656 bytes ...remove_empty_lines_advance.cpython-311.pyc | Bin 4022 -> 4057 bytes image_resolution_adjuster.py | 232 ++++++++++++++++++ 8 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 __pycache__/image_resolution_adjuster.cpython-311.pyc create mode 100644 image_resolution_adjuster.py diff --git a/__init__.py b/__init__.py index c4e0078..daee5eb 100644 --- a/__init__.py +++ b/__init__.py @@ -2,6 +2,8 @@ from .image_scale_calculator import ImageScaleCalculator from .remove_empty_lines import RemoveEmptyLinesAndLeadingSpaces from .remove_empty_lines_advance import RemoveEmptyLinesAndLeadingSpacesAdvance from .dynamic_image_input import DynamicImageInputs +from .image_resolution_adjuster import ImageResolutionAdjuster + # 可以在此处添加任何初始化代码 @@ -10,7 +12,8 @@ NODE_CLASS_MAPPINGS = { "ImageScaleCalculator": ImageScaleCalculator, "RemoveEmptyLinesAndLeadingSpaces": RemoveEmptyLinesAndLeadingSpaces, "RemoveEmptyLinesAndLeadingSpacesAdvance": RemoveEmptyLinesAndLeadingSpacesAdvance, - "DynamicImageInputs": DynamicImageInputs + "DynamicImageInputs": DynamicImageInputs, + "ImageResolutionAdjuster": ImageResolutionAdjuster } # 友好/人类可读的节点标题映射 @@ -18,7 +21,8 @@ NODE_DISPLAY_NAME_MAPPINGS = { "ImageScaleCalculator": "Image Scale Calculator Node", "RemoveEmptyLinesAndLeadingSpaces": "Remove Empty Lines & Leading Spaces", "RemoveEmptyLinesAndLeadingSpacesAdvance": "Remove Empty Lines & Leading Spaces Advance", - "DynamicImageInputs": "Dynamic Image Inputs" + "DynamicImageInputs": "Dynamic Image Inputs", + "ImageResolutionAdjuster": "Image Resolution Adjuster" } # 你可以在此处添加更多的配置或注册逻辑 diff --git a/__pycache__/__init__.cpython-311.pyc b/__pycache__/__init__.cpython-311.pyc index d0c8b6f4c19644652911a7262bf53c84f6dff6a5..c20c90094c471d71deff5158aefbd54ce40a2a16 100644 GIT binary patch delta 455 zcmdnX_LyCLIWI340}$xcWTl^CVPJR+;=lkKl<_%fqPnS33PTEO4o5C$6elA?Dq|{h zDr+ixDrXAY9M&kV6!sL36wVZ`6mBq|JB25hL6di4U9%D6EpgA>#Prml)Z+Y{(vr;l zJjax*(&CcTB2CsJW}pQ{KwBA#SV08Hz9RO?!i*hqRgz#`3J7fqFnxZSJd@`!7Rg9v zg3OICf*Ty42sIgK1`m@>eW9CGjH9Q!b4Y%EPH~KLer{T2sHaP6S!zyxK`M+NU!Iwl zl3!jNUyxr^l9-eOmxxIQx-vgEJ}*Bd6|OrzATcwqBr`AF87Nv5T9OGgI6gizFS8^* zUaz3?7l%!5eoARhs$G!~0|x^GBhW*|3n#B(3W&VHV0Qr(ec)q|HN2tWaYH}shLp|? yd9x4PY~oBG7=XkD2H_7P46;@?G<Cow;*G_)i$Cni2VGcU6wK3=b& z@)w6qZhlH>PO4pz0MJ}UATI8lY{eYl_<@H(*6@ag#|{0k8&WzSI9bJ+J}>}@3k<>^ ggcxM4ZfN-4(2uzxWdM|t14+pNrKBLJh!1EE0FQA+KmY&$ diff --git a/__pycache__/dynamic_image_input.cpython-311.pyc b/__pycache__/dynamic_image_input.cpython-311.pyc index 43e03c398a0af33a2fa91016859f0b93228b40e7..34394e90e278c75ffe54b6c19c7b48a0d6469451 100644 GIT binary patch delta 1067 zcmZuv-A~g{6z^@E}-6H#Nt_%Ip55?l;IjJjl*ZJE`roxL3sGr}Yg z8A|vlh6Rn`!4K3(!W#(TZy3ghr4K$)hEI0U2ji2s8!k~i55JuIJLlYU?){zh%3-Jd zjm>7okgYOz!jyU3-T^L-Gw19#tgK}KyHUYzzlyo7^RH|1Tk-oSO`DruTTE{Z_viZ; z^V0(xD~dMwDnGxZy?AV;H?8cnb8=h~U}Kpu5?G#*8)@yypf>jY>r!T8?j^cM8+p36 z@J>mAnm!{(wMg8(I4^Omx{Z&9!d&p=TcDD@%bu3zx0oBK1QUS}pn2$D$xDp^kFTYv zLlh%0&?H8?dOCexuA7U9G49VfnBWCgOu%4Fl;qH@NI4K-;!qZ&K|y4>VzojOWYv`r zFUY(QZbGcoDf1DioFKejCu#_*5u`BPjyY>H*JrKSeW$Y2>8$1Scf@1THUwxsb8%|u z1|6zBCW#COVX#CgGsFduQN9oj=T8Q34C^I&O-W+Lc*_=J!E407FUO>sr0L<#BtC;H z`%Oo8G$ipZfaJmB1yriN9LSF;2f?ns@^_aVj}-n#g=5F=CPD_gsl<9Zwf;O^l2d!O zl21P}RQWKa4K93Je)4s4P8%CppIO$HN7oiU(si4n)YboS8|vu%hjg*waYI4F%I*KV z2XZ_X;Tmb>6F5@Ry!2;5H=&Ze%tfJUg>p!eVS<-$tL9KF#tE#OR85eJbgAaj_>vvH zTm^Sk&<#oC7W+yS$df1p4_w|JAr$2qpRq(fAr_b6iNE!rQ5p-cAw;59VO7;b=3MpO zskVu>asQ-W$MEg0BBZ@To}qg=$}yT8PG(wHsl%VC!#W0Ru36XY@tkAVlx@P639UNl z&kj24pnoE2s3&XLE!oiBes`tv%jB=9Y;W%9Z1)HKp36!zc@$7elym_`86|i74`61e zj+@CdI)Qt&#H`&NNI<^&*0$J}ngjyTh a1J5GR2>^hO*8`Nl6$%FT<3EAo{J#NyDo_*v delta 606 zcmeAYe8$7KoR^o20SE%OWTrE4Oymn;w40c0$<@LT#g)Pl%%I7+ag{Vvz27a4qSV6D z%%aqkTWp!RiRr0^D;aOGdipxLyRKx=WW2>#T+9eGMd4SZr&Wxjr@M2EbAE1GWvFL- zd1hWpetB_xUTQf^EGD_MxFkO}J}*BdwHPKC?~|CHRvKE8nG=&znU|QGnH&$cC_Xc< zVDd9&BRvD4`Ncv&qJiOofYgkL1yvVhOfK-7Uf?kO3>0N3Vh0kMj3KvJQt~rPCdaVY zGGaWXrrdcAZFQyL@CbBunPOt)AwOHy--Z?Pp76r|>* zXtLg7DNfBvyTz7Wo>-I)6bHMa_!eXKEyl89R-hdUAW*~&vXT!-REfJl-0KMn7tg$c z(vo65kQ1zclEwBwqJiOtpl}D<0}-j|K9hVV`k7Dh`@q1+DGMe#T{;{)3UBZT_4{`D z&QQF_BXfmE<^mW!5D@FAy1*e>#0xaUPm_Bx54+#w40aVpzRA7pij47-*RxA_#V|6k z34UN=WHkdC$7=SG8OUvkh6u1Rh{!eg+z^#%@Vmh;+Tihk-?+i!0}C6g)CUGkVzMZQ lj;8|9Do{)on*)gt%#4hTADHYJf$A}dk07xxSR}yi1ps&$uGs(p diff --git a/__pycache__/image_resolution_adjuster.cpython-311.pyc b/__pycache__/image_resolution_adjuster.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29a2a8142b798ad34e3856fa4f1edfdc4ed0c36d GIT binary patch literal 11046 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 DEji5b literal 0 HcmV?d00001 diff --git a/__pycache__/image_scale_calculator.cpython-311.pyc b/__pycache__/image_scale_calculator.cpython-311.pyc index 7c047c273ed3531db3f71735bcb1287a8f801dba..4aeb30fc0a1a295e4e277a4d1f62c0bf9a574f20 100644 GIT binary patch delta 131 zcmdn)e#@P2IWI340}xzH&PvZy-N={ClUDC$731jX?i`YzpHm#;oS&Ok8S3ehT9%rV zUyusp$Cqd3rR0|v#~0)ml_VzRz$IdmON&eLbK~>!Q&Qo&;{y^i^GY)F(w%{#MWH2` MImMgz@cb4700S#AbpQYW delta 71 zcmccRzTKT~IWI340}%Y_%}n2*vXL*FM<&M8D#p>%-8sfNKR2y1)HA+3GcP5-yf{8D awS4k=9yv~*#Qe0<(2~rY&G&hJiva*v#~F(N diff --git a/__pycache__/remove_empty_lines.cpython-311.pyc b/__pycache__/remove_empty_lines.cpython-311.pyc index b17e3aa1963f665fdbef15153acd733d2c6c81fd..98a5e829274d72b5c8b7d33ea4f472097ee429d6 100644 GIT binary patch delta 103 zcmZ1~b3%rDIWI340}xzH&f3U*jmfOq%__#x)7?2FKR>59#yLMXtuoZpCABOyC%+&S z#*Z)0%uC5HFODzBFDgk)%1NF4mq|`2ATcwqBr`AFIX@+}D6}Lqr+BjpGb1+uCiohvs8wAIWI340}$x0$=t|&jY%fL(<;W%)7?47IX^e8GSoA^JTosPzq~j;FSUHK WII|q5Phx&rX=q7i&SrOJMs5JX-xW3h diff --git a/__pycache__/remove_empty_lines_advance.cpython-311.pyc b/__pycache__/remove_empty_lines_advance.cpython-311.pyc index 999003ee8c3a70f9f1bec4e75f3a8890eafe68cf..70f4050187676dabd942be2bf017897d4bbbc2a8 100644 GIT binary patch delta 103 zcmdlce^Z`&IWI340}xzH&f3Tw#%$K?W)FykopPy44>FylkoS&Ok8R{8do|%`DUtS!ams&n~ WI target_ratio: + new_width = target_width + new_height = int(target_width / img_ratio) + else: + new_height = target_height + new_width = int(target_height * img_ratio) + resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + padded_img = Image.new('RGB', (target_width, target_height), 'black') + x_offset = (target_width - new_width) // 2 + y_offset = (target_height - new_height) // 2 + padded_img.paste(resized_img, (x_offset, y_offset)) + return np.array(padded_img).astype(np.float32)/255.0, new_width, new_height + + elif method == 'cover': + # Cover: 缩放图像以覆盖目标尺寸,保持宽高比,可能裁剪 + img_ratio = img_width / img_height + target_ratio = target_width / target_height + if img_ratio > target_ratio: + new_height = target_height + new_width = int(target_height * img_ratio) + else: + new_width = target_width + new_height = int(target_width / img_ratio) + resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + x_offset = (new_width - target_width) // 2 + y_offset = (new_height - target_height) // 2 + cropped_img = resized_img.crop((x_offset, y_offset, x_offset + target_width, y_offset + target_height)) + return np.array(cropped_img).astype(np.float32)/255.0 , target_width, target_height + + elif method == 'fill': + # Fill: 拉伸图像以填充目标尺寸,忽略宽高比,可能变形 + resized_img = img.resize((target_width, target_height), Image.Resampling.LANCZOS) + return np.array(resized_img).astype(np.float32)/255.0, target_width, target_height + + elif method == 'inside': + # Inside: 和 contain 相同,保持宽高比,缩小或不改变图像使其完全适合容器 + img_ratio = img_width / img_height + target_ratio = target_width / target_height + if img_ratio > target_ratio: + new_width = target_width + new_height = int(target_width / img_ratio) + else: + new_height = target_height + new_width = int(target_height * img_ratio) + resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + padded_img = Image.new('RGB', (target_width, target_height), 'black') + x_offset = (target_width - new_width) // 2 + y_offset = (target_height - new_height) // 2 + padded_img.paste(resized_img, (x_offset, y_offset)) + return np.array(padded_img).astype(np.float32)/255.0, target_width, target_height + + elif method == 'outside': + # Outside: 和 cover 相同,保持宽高比,放大或不改变图像使其完全覆盖容器 + img_ratio = img_width / img_height + target_ratio = target_width / target_height + if img_ratio > target_ratio: + new_height = target_height + new_width = int(target_height * img_ratio) + else: + new_width = target_width + new_height = int(target_width / img_ratio) + resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + x_offset = (new_width - target_width) // 2 + y_offset = (new_height - target_height) // 2 + cropped_img = resized_img.crop((x_offset, y_offset, x_offset + target_width, y_offset + target_height)) + return np.array(cropped_img).astype(np.float32)/255.0 , target_width, target_height + +def pad_image(image, target_width, target_height, position='center'): + """Pad an image to the target dimensions. + position: 'center' (居中), 'top' (顶部), 'bottom' (底部), 'left' (左边), 'right' (右边) + """ + img = Image.fromarray(np.clip(255. * image.cpu().numpy(), 0, 255).astype(np.uint8)) + img_width, img_height = img.size + + padded_img = Image.new('RGB', (target_width, target_height), 'black') # 创建黑色背景 + + if position == 'center': + x_offset = (target_width - img_width) // 2 + y_offset = (target_height - img_height) // 2 + elif position == 'top': + x_offset = (target_width - img_width) // 2 + y_offset = 0 + elif position == 'bottom': + x_offset = (target_width - img_width) // 2 + y_offset = target_height - img_height + elif position == 'left': + x_offset = 0 + y_offset = (target_height - img_height) // 2 + elif position == 'right': + x_offset = target_width - img_width + y_offset = (target_height - img_height) // 2 + else: + raise ValueError(f"Invalid pad position: {position}") + + padded_img.paste(img, (x_offset, y_offset)) + return np.array(padded_img).astype(np.float32) / 255.0, target_width, target_height + +def calculate_resolution(aspect_ratio, scale_factor, max_width, max_height, min_width, min_height): + """Calculate the target resolution based on aspect ratio and scale factor.""" + + base_resolutions = { + "1:1": (1024, 1024), + "1152x896": (1152, 896), + "896x1152": (896, 1152), + "1216x832": (1216, 832), + "832x1216": (832, 1216), + "1344x768": (1344, 768), + "768x1344": (768, 1344), + "1536x640": (1536, 640), + "640x1536": (640, 1536), + } + + if aspect_ratio in base_resolutions: + base_width, base_height = base_resolutions[aspect_ratio] + else: # default to 1:1 + base_width = 1024 + base_height = 1024 + + target_width = int(base_width * scale_factor) + target_height = int(base_height * scale_factor) + + + return target_width, target_height, base_width, base_height + +def get_aspect_ratio_string(width, height): + """Get the aspect ratio string from width and height""" + common_divisor = gcd(width, height) + aspect_width = width // common_divisor + aspect_height = height // common_divisor + return f"{aspect_width}:{aspect_height}" + +class ImageResolutionAdjuster: + @classmethod + def INPUT_TYPES(s): + + resolutions = ["1:1 (1024x1024)", + f"{get_aspect_ratio_string(1152,896)} (1152x896)", + f"{get_aspect_ratio_string(896,1152)} (896x1152)", + f"{get_aspect_ratio_string(1216,832)} (1216x832)", + f"{get_aspect_ratio_string(832,1216)} (832x1216)", + f"{get_aspect_ratio_string(1344,768)} (1344x768)", + f"{get_aspect_ratio_string(768,1344)} (768x1344)", + f"{get_aspect_ratio_string(1536,640)} (1536x640)", + f"{get_aspect_ratio_string(640,1536)} (640x1536)"] + return { + "required": { + "images": ("IMAGE",), + "target_resolution": (resolutions,), + "extend_mode": (["contain", "cover", "fill", "inside", "outside", "top", "bottom", "left", "right", "center"],), + "scale_factor": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 10.0, "step": 0.1}), # scale_factor 最小值保留小数点后1位 + "max_width": ("INT", {"default": 2048, "min": 1, "max": 8192, "step": 1}), + "max_height": ("INT", {"default": 2048, "min": 1, "max": 8192, "step": 1}), + "min_width": ("INT", {"default": 640, "min": 1, "max": 8192, "step": 1}), # 默认最小宽度 + "min_height": ("INT", {"default": 640, "min": 1, "max": 8192, "step": 1}), # 默认最小高度 + } + } + + RETURN_TYPES = ("IMAGE", "INT", "INT") + RETURN_NAMES = ("images", "width", "height") + FUNCTION = "adjust_resolution" + CATEGORY = "🎨Painting👓Coder/🖼️Image" + + def adjust_resolution(self, images, target_resolution, extend_mode, scale_factor, max_width, max_height, min_width, min_height): + + output_images = [] + output_width = 0 + output_height = 0 + + # Extract aspect ratio from the target_resolution string + aspect_ratio = target_resolution.split(" ")[0] + + target_width, target_height, base_width, base_height = calculate_resolution(aspect_ratio, scale_factor, max_width, max_height, min_width, min_height) + + for image in images: + img = image + + # Calculate the initial target dimensions based on scale_factor + + + # Apply maximum resolution constraint + current_max = max(target_width, target_height) + if current_max > max_width or current_max > max_height: + scale = min(max_width / current_max, max_height / current_max) + target_width = int(target_width * scale) + target_height = int(target_height * scale) + + + # Apply minimum resolution constraint + current_min = min(target_width, target_height) + if current_min < min_width or current_min < min_height: + scale = max(min_width / current_min, min_height / current_min) + target_width = int(target_width * scale) + target_height = int(target_height * scale) + + if extend_mode in ["contain", "cover", "fill", "inside", "outside"]: + scaled_image, width, height = resize_image(img, target_width, target_height, method=extend_mode) + elif extend_mode in ["top", "bottom", "left", "right", "center"]: + scaled_image, width, height = pad_image(img, target_width, target_height, position=extend_mode) + else: + raise ValueError(f"Invalid extend_mode: {extend_mode}") + + output_images.append(torch.from_numpy(scaled_image).unsqueeze(0)) + output_width = width + output_height = height + + return (torch.cat(output_images, dim=0), output_width, output_height)