diff --git a/LICENSE b/LICENSE
index a55a20e..08a6e41 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2025 Karpich Dmitry
+Copyright (c) 2025-2026 Karpich Dmitry
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Readme.md b/Readme.md
index 879e22c..a0739e8 100644
--- a/Readme.md
+++ b/Readme.md
@@ -2,17 +2,17 @@
## Image Fit Calculator
-
+
The ComfyUI custom node **Image Fit Calculator** is designed to automatically calculate new image parameters based on a given latent and original image. Specifically, this node can perform calculations for resizing an image and provide data for paddings to control its placement within the latent space. Additionally, it includes settings that allow users to specify horizontal or vertical offsets as well as reduce the size of the image. This node performs only computational tasks, while actual operations on the image may be carried out by external nodes if they have the capability to use input data to manipulate the result.
-
+
In the provided workflow example, one can see how the ComfyUI node integrates with other components to streamline the process of image manipulation. This modular approach ensures flexibility and extensibility, enabling developers to easily incorporate new functionalities or optimize existing ones.
-
+
If you encounter any bugs or have ideas for improving the ComfyUI node, feel free to create an issue or submit a pull request. Your contributions are highly appreciated and will help enhance this powerful tool for image processing automation.
diff --git a/modules/image_tool.py b/modules/image_tool.py
index 54487f9..7d4a3d9 100644
--- a/modules/image_tool.py
+++ b/modules/image_tool.py
@@ -22,7 +22,7 @@ class OFOImageFit:
"required": {
"latent": ("LATENT",),
"image": ("IMAGE",),
- "latent_scale": (SCALE_OPTIONS,),
+ "latent_scale": (SCALE_OPTIONS, {"default": SCALE_8X}),
},
"optional": {
"width_position": (
@@ -108,24 +108,46 @@ class OFOImageFit:
tuple: A tuple containing six integers representing the new width, height, top, right, bottom, and left padding values.
"""
scale_factor = SCALE_FACTOR_MAP[latent_scale]
-
+
latent_height, latent_width = get_latent_size(latent, scale_factor)
image_height, image_width = get_image_size(image)
- # get minimum scale
+ # Compute base scaling (fit inside latent)
scale_w = latent_width / image_width
scale_h = latent_height / image_height
min_scale = min(scale_w, scale_h) * scale
- # scale image
- new_image_width = round(image_width * min_scale)
- new_image_height = round(image_height * min_scale)
+ # Initial candidate dimensions (floored to avoid exceeding latent)
+ raw_width = int(image_width * min_scale)
+ raw_height = int(image_height * min_scale)
- # calculate padding
- padding_left = round((latent_width - new_image_width) * width_position)
- padding_right = latent_width - new_image_width - padding_left
- padding_bottom = round((latent_height - new_image_height) * height_position)
- padding_top = latent_height - new_image_height - padding_bottom
+ # Ensure raw dimensions do not exceed latent bounds (safety)
+ raw_width = min(raw_width, latent_width)
+ raw_height = min(raw_height, latent_height)
+
+ # ----- Adjust to multiples of 8 -----
+ # We prefer rounding down to the nearest multiple of 8 (keep inside latent).
+ # But we also need to ensure we don't lose too much size.
+ # Let's find the largest multiple of 8 <= raw_width and <= raw_height.
+ target_width = (raw_width // 8) * 8
+ target_height = (raw_height // 8) * 8
+
+ # However, if the difference is too large (more than 7 pixels), we could try rounding up if still fits.
+ # But to be safe and keep exact fit, we just round down.
+ # If rounding down reduces size too much, the user can increase `scale`.
+ new_image_width = target_width
+ new_image_height = target_height
+
+ # ----- Recompute paddings based on final aligned sizes -----
+ # Horizontal padding
+ remaining_width = latent_width - new_image_width
+ padding_left = int(remaining_width * width_position)
+ padding_right = remaining_width - padding_left
+
+ # Vertical padding
+ remaining_height = latent_height - new_image_height
+ padding_top = int(remaining_height * height_position)
+ padding_bottom = remaining_height - padding_top
return (
new_image_width,
diff --git a/pyproject.toml b/pyproject.toml
index b3edd70..f46ba07 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[project]
name = "comfyui-oneforone"
description = "Node:Image Fit Calculator"
-version = "1.0.1"
+version = "2.0.1"
license = {file = "LICENSE"}
dependencies = ["numpy"]
diff --git a/workflow/fit_calculator_example.json b/workflow/fit_calculator_example.json
index c87b96c..fe46eab 100644
--- a/workflow/fit_calculator_example.json
+++ b/workflow/fit_calculator_example.json
@@ -1 +1 @@
-{"last_node_id":18,"last_link_id":26,"nodes":[{"id":10,"type":"JWImageResize","pos":[1431.3875732421875,558.186279296875],"size":[315,106],"flags":{},"order":3,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":12},{"name":"height","type":"INT","link":14,"widget":{"name":"height"}},{"name":"width","type":"INT","link":13,"widget":{"name":"width"}}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[11],"slot_index":0}],"properties":{"Node name for S&R":"JWImageResize"},"widgets_values":[512,512,"bicubic"]},{"id":2,"type":"LoadImage","pos":[621.5283203125,794.5676879882812],"size":[372.7273864746094,534.0333251953125],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[10,12],"slot_index":0},{"name":"MASK","type":"MASK","links":null}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["ComfyUI_temp_vbgus_00020__cr.png","image"]},{"id":11,"type":"ImagePadForOutpaint","pos":[1426.8939208984375,717.5982666015625],"size":[315,174],"flags":{},"order":4,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":11},{"name":"left","type":"INT","link":15,"widget":{"name":"left"}},{"name":"right","type":"INT","link":16,"widget":{"name":"right"}},{"name":"top","type":"INT","link":17,"widget":{"name":"top"}},{"name":"bottom","type":"INT","link":18,"widget":{"name":"bottom"}}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[19],"slot_index":0,"shape":3},{"name":"MASK","type":"MASK","links":[],"slot_index":1,"shape":3}],"properties":{"Node name for S&R":"ImagePadForOutpaint"},"widgets_values":[256,256,256,256,100],"color":"#223","bgcolor":"#335"},{"id":12,"type":"PreviewImage","pos":[1040.3717041015625,942.8541259765625],"size":[699.3174438476562,384.62847900390625],"flags":{},"order":5,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":19}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":1,"type":"SDXL Empty Latent Image (rgthree)","pos":[624.0381469726562,569.5147094726562],"size":[307.03814697265625,147.67324829101562],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[{"name":"LATENT","type":"LATENT","links":[26],"slot_index":0},{"name":"CLIP_WIDTH","type":"INT","links":null},{"name":"CLIP_HEIGHT","type":"INT","links":null}],"properties":{"Node name for S&R":"SDXL Empty Latent Image (rgthree)"},"widgets_values":[" 896 x 1152 (portrait)",2,1]},{"id":3,"type":"OFO Image Fit","pos":[1013.9083862304688,568.6777954101562],"size":[315,206],"flags":{},"order":2,"mode":0,"inputs":[{"name":"latent","type":"LATENT","link":26},{"name":"image","type":"IMAGE","link":10}],"outputs":[{"name":"IMAGE_WIDTH","type":"INT","links":[13],"slot_index":0},{"name":"IMAGE_HEIGHT","type":"INT","links":[14],"slot_index":1},{"name":"PAD_TOP","type":"INT","links":[17],"slot_index":2},{"name":"PAD_RIGHT","type":"INT","links":[16],"slot_index":3},{"name":"PAD_BOTTOM","type":"INT","links":[18],"slot_index":4},{"name":"PAD_LEFT","type":"INT","links":[15],"slot_index":5}],"properties":{"Node name for S&R":"OFO Image Fit"},"widgets_values":[0.5,0.5,1]}],"links":[[10,2,0,3,1,"IMAGE"],[11,10,0,11,0,"IMAGE"],[12,2,0,10,0,"IMAGE"],[13,3,0,10,2,"INT"],[14,3,1,10,1,"INT"],[15,3,5,11,1,"INT"],[16,3,3,11,2,"INT"],[17,3,2,11,3,"INT"],[18,3,4,11,4,"INT"],[19,11,0,12,0,"IMAGE"],[26,1,0,3,0,"LATENT"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.2100000000000002,"offset":[-281.8721688302316,-499.88342397357997]}},"version":0.4}
\ No newline at end of file
+{"id":"439813ff-572b-4bc3-aeca-d2fd9f3fc2ed","revision":0,"last_node_id":35,"last_link_id":50,"nodes":[{"id":2,"type":"LoadImage","pos":[642.9626165771484,792.4934286499024],"size":[372.7273864746094,534.0333251953125],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","slot_index":0,"links":[28,29]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["ComfyUI_temp_uiahb_00014_.png","image"]},{"id":12,"type":"PreviewImage","pos":[1033.4576293945313,942.8541259765625],"size":[699.3174438476562,384.62847900390625],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":19}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":11,"type":"ImagePadForOutpaint","pos":[1410.9282641601567,727.9068658447266],"size":[315,174],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":32},{"localized_name":"left","name":"left","type":"INT","widget":{"name":"left"},"link":38},{"localized_name":"top","name":"top","type":"INT","widget":{"name":"top"},"link":35},{"localized_name":"right","name":"right","type":"INT","widget":{"name":"right"},"link":36},{"localized_name":"bottom","name":"bottom","type":"INT","widget":{"name":"bottom"},"link":37},{"localized_name":"feathering","name":"feathering","type":"INT","widget":{"name":"feathering"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","slot_index":0,"links":[19]},{"localized_name":"MASK","name":"MASK","type":"MASK","slot_index":1,"links":[]}],"properties":{"Node name for S&R":"ImagePadForOutpaint"},"widgets_values":[256,256,256,256,100],"color":"#223","bgcolor":"#335"},{"id":23,"type":"RTXVideoSuperResolution","pos":[1422.0320145525259,559.28999199827],"size":[285.81015625,130],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":29},{"localized_name":"resize_type","name":"resize_type","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"resize_type"},"link":null},{"localized_name":"resize_type.width","name":"resize_type.width","type":"INT","widget":{"name":"resize_type.width"},"link":33},{"localized_name":"resize_type.height","name":"resize_type.height","type":"INT","widget":{"name":"resize_type.height"},"link":34},{"localized_name":"quality","name":"quality","type":"COMBO","widget":{"name":"quality"},"link":null}],"outputs":[{"localized_name":"upscaled_images","name":"upscaled_images","type":"IMAGE","links":[32]}],"properties":{"Node name for S&R":"RTXVideoSuperResolution"},"widgets_values":["target dimensions",1920,1080,"ULTRA"]},{"id":20,"type":"OFO Image Fit","pos":[1059.8035898699086,584.5642311950483],"size":[270,230],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"latent","name":"latent","type":"LATENT","link":27},{"localized_name":"image","name":"image","type":"IMAGE","link":28},{"localized_name":"latent_scale","name":"latent_scale","type":"COMBO","widget":{"name":"latent_scale"},"link":null},{"localized_name":"width_position","name":"width_position","shape":7,"type":"FLOAT","widget":{"name":"width_position"},"link":null},{"localized_name":"height_position","name":"height_position","shape":7,"type":"FLOAT","widget":{"name":"height_position"},"link":null},{"localized_name":"scale","name":"scale","shape":7,"type":"FLOAT","widget":{"name":"scale"},"link":null}],"outputs":[{"localized_name":"IMAGE_WIDTH","name":"IMAGE_WIDTH","type":"INT","links":[33]},{"localized_name":"IMAGE_HEIGHT","name":"IMAGE_HEIGHT","type":"INT","links":[34]},{"localized_name":"PAD_TOP","name":"PAD_TOP","type":"INT","links":[35]},{"localized_name":"PAD_RIGHT","name":"PAD_RIGHT","type":"INT","links":[36]},{"localized_name":"PAD_BOTTOM","name":"PAD_BOTTOM","type":"INT","links":[37]},{"localized_name":"PAD_LEFT","name":"PAD_LEFT","type":"INT","links":[38]}],"properties":{"Node name for S&R":"OFO Image Fit"},"widgets_values":["SD, Qwen (8x)",1,1,0.5]},{"id":1,"type":"SDXL Empty Latent Image (rgthree)","pos":[659.3008880615233,591.640376281738],"size":[307.03814697265625,147.67324829101562],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"dimensions","name":"dimensions","type":"COMBO","widget":{"name":"dimensions"},"link":null},{"localized_name":"clip_scale","name":"clip_scale","type":"FLOAT","widget":{"name":"clip_scale"},"link":null},{"localized_name":"batch_size","name":"batch_size","type":"INT","widget":{"name":"batch_size"},"link":null}],"outputs":[{"localized_name":"LATENT","name":"LATENT","type":"LATENT","slot_index":0,"links":[27]},{"localized_name":"CLIP_WIDTH","name":"CLIP_WIDTH","type":"INT","links":null},{"localized_name":"CLIP_HEIGHT","name":"CLIP_HEIGHT","type":"INT","links":null}],"properties":{"Node name for S&R":"SDXL Empty Latent Image (rgthree)"},"widgets_values":["1152 x 896 (landscape)",2,1]}],"links":[[19,11,0,12,0,"IMAGE"],[27,1,0,20,0,"LATENT"],[28,2,0,20,1,"IMAGE"],[29,2,0,23,0,"IMAGE"],[32,23,0,11,0,"IMAGE"],[33,20,0,23,2,"INT"],[34,20,1,23,3,"INT"],[35,20,2,11,2,"INT"],[36,20,3,11,3,"INT"],[37,20,4,11,4,"INT"],[38,20,5,11,1,"INT"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.8264462809917354,"offset":[385.1799165998192,-255.48019509275272]}},"version":0.4}
\ No newline at end of file