From 7de0ffecd3a895dbc9ba952bcbc5bc10e8ac3a37 Mon Sep 17 00:00:00 2001 From: malkuthro <166633396+malkuthro@users.noreply.github.com> Date: Sat, 18 Oct 2025 21:40:40 +0200 Subject: [PATCH] make preDefined pad and panel colors --- k_easy_resize.py | 48 +++++++++++++++++++++++++++++++--------------- web/ai_pipeline.js | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/k_easy_resize.py b/k_easy_resize.py index d5d2feb..22d9891 100644 --- a/k_easy_resize.py +++ b/k_easy_resize.py @@ -11,15 +11,17 @@ class EasyResize: "base_on": (["Width", "Height"], {"default": "Width"}), "base_size": ("INT", {"default": 512, "min": 1, "max": MAX_RESOLUTION, "step": 1}), "aspect_ratio": ("STRING", {"default": "16:9"}), + "divisible_by": ("INT", {"default": 32, "min": 1, "max": 128, "step": 1}), "upscale_method": (["nearest-exact", "bilinear", "area", "bicubic", "lanczos"], {"default": "nearest-exact"}), "keep_proportion": (["stretch", "letterbox", "pillarbox"], {"default": "stretch"}), - "pad_color": ("STRING", {"default": "0, 0, 0"}), "crop_position": (["top", "bottom", "left", "right", "center"], {"default": "center"}), - "divisible_by": ("INT", {"default": 32, "min": 1, "max": 128, "step": 1}), + "pad_color_mode": (["White", "Black", "Gray", "Custom"], {"default": "Black"}), + "panel_color_mode": (["White", "Black", "Gray", "Custom"], {"default": "Black"}), "device": (["cpu", "cuda"], {"default": "cpu"}), }, "optional": { "mask": ("MASK",), + "pad_color": ("STRING", {"default": "0, 0, 0"}), "panel_color": ("STRING", {"default": "0, 0, 0"}), } } @@ -33,10 +35,11 @@ Adjusts the input image to a target resolution based on a base dimension (width an aspect ratio (e.g., '16:9' for landscape, '9:16' for portrait), ensuring both dimensions are divisible by the specified value. Supports stretch or pad/crop modes for proportion control. Outputs the resized image, optional mask, and final width/height for VFX pipeline integration. -Also outputs a solid color panel (canvas) of the target size using the specified panel_color. +Also outputs a solid color panel (canvas) of the target size using the specified panel_color_mode and optional custom panel_color. +When selecting 'Custom' for pad_color_mode or panel_color_mode, enter the color in the corresponding field as comma-separated floats, e.g., '0.5, 0.5, 0.5' for gray. """ - def adjust_to_aspect(self, image, base_on, base_size, aspect_ratio, upscale_method, keep_proportion, pad_color, crop_position, divisible_by, device, mask=None, panel_color="0, 0, 0"): + def adjust_to_aspect(self, image, base_on, base_size, aspect_ratio, upscale_method, keep_proportion, pad_color_mode, crop_position, divisible_by, device, panel_color_mode, mask=None, pad_color="0, 0, 0", panel_color="0, 0, 0"): def round_to_nearest_multiple(number, multiple): return multiple * round(number / multiple) @@ -78,6 +81,31 @@ Also outputs a solid color panel (canvas) of the target size using the specified has_alpha = (C == 4) + # Color map for modes + color_map = { + "White": [1.0, 1.0, 1.0], + "Black": [0.0, 0.0, 0.0], + "Gray": [0.5, 0.5, 0.5], + } + + # Determine pad_color_list + if pad_color_mode == "Custom": + pad_color_list = [float(x.strip()) for x in pad_color.split(',')] + else: + pad_color_list = color_map.get(pad_color_mode, [0.0, 0.0, 0.0]) # Default to black if invalid + + if len(pad_color_list) != 3: + raise ValueError("Pad color must be three comma-separated floats, e.g., '0, 0, 0'.") + + # Determine panel_color_list + if panel_color_mode == "Custom": + panel_color_list = [float(x.strip()) for x in panel_color.split(',')] + else: + panel_color_list = color_map.get(panel_color_mode, [0.0, 0.0, 0.0]) # Default to black if invalid + + if len(panel_color_list) != 3: + raise ValueError("Panel color must be three comma-separated floats, e.g., '0, 0, 0'.") + if keep_proportion == "stretch": # Simple resize out_image = common_upscale(image, target_width, target_height, upscale_method, "disabled") @@ -116,15 +144,10 @@ Also outputs a solid color panel (canvas) of the target size using the specified pad_l = total_pad_w // 2 pad_r = total_pad_w - pad_l - # Parse pad_color - pad_color = [float(x.strip()) for x in pad_color.split(',')] - if len(pad_color) != 3: - raise ValueError("Pad color must be three comma-separated floats, e.g., '0, 0, 0'.") - # Create background with pad color (RGB or RGBA) pad_channels = 4 if has_alpha else 3 pad_color_tensor = torch.zeros((1, pad_channels, 1, 1), dtype=image.dtype, device=device) - pad_color_tensor[0, :3, 0, 0] = torch.tensor(pad_color, dtype=image.dtype, device=device) + pad_color_tensor[0, :3, 0, 0] = torch.tensor(pad_color_list, dtype=image.dtype, device=device) if has_alpha: # Default alpha to 1 (opaque) for padding pad_color_tensor[0, 3, 0, 0] = 1.0 @@ -142,11 +165,6 @@ Also outputs a solid color panel (canvas) of the target size using the specified out_mask = out_mask.movedim(1, -1).squeeze(-1) # Squeeze last dim (channel=1) -> [B, H', W'] # Create color panel - # Parse panel_color - panel_color_list = [float(x.strip()) for x in panel_color.split(',')] - if len(panel_color_list) != 3: - raise ValueError("Panel color must be three comma-separated floats, e.g., '0, 0, 0'.") - # Create panel tensor (B=1, C=3, H=target_height, W=target_width) panel_channels = 3 # RGB, no alpha color_panel = torch.zeros((1, panel_channels, target_height, target_width), dtype=image.dtype, device=device) diff --git a/web/ai_pipeline.js b/web/ai_pipeline.js index 453cf6a..abb2dc3 100644 --- a/web/ai_pipeline.js +++ b/web/ai_pipeline.js @@ -47,5 +47,41 @@ app.registerExtension({ }, { serialize: false }); }; } + }, + async nodeCreated(node) { + if (node.comfyClass !== "EasyResize") return; + + // Function to update widgets for a mode + const updateWidgets = (modeName, colorName, value) => { + const colorWidgetIndex = node.widgets.findIndex(w => w.name === colorName); + if (value === "Custom") { + if (colorWidgetIndex === -1) { + node.addWidget("string", colorName, "0, 0, 0", null, { multiline: false }); + } + } else { + if (colorWidgetIndex !== -1) { + node.widgets.splice(colorWidgetIndex, 1); // Remove + } + } + node.setDirtyCanvas(true, true); + }; + + // Pad color mode + const padModeWidget = node.widgets.find(w => w.name === "pad_color_mode"); + const origPadCallback = padModeWidget.callback; + padModeWidget.callback = (value) => { + if (origPadCallback) origPadCallback.call(this, value); + updateWidgets("pad_color_mode", "pad_color", value); + }; + updateWidgets("pad_color_mode", "pad_color", padModeWidget.value); + + // Panel color mode + const panelModeWidget = node.widgets.find(w => w.name === "panel_color_mode"); + const origPanelCallback = panelModeWidget.callback; + panelModeWidget.callback = (value) => { + if (origPanelCallback) origPanelCallback.call(this, value); + updateWidgets("panel_color_mode", "panel_color", value); + }; + updateWidgets("panel_color_mode", "panel_color", panelModeWidget.value); } }); \ No newline at end of file