From 3078ffa3be444d2dee0b82cb30110905c10d48f7 Mon Sep 17 00:00:00 2001 From: filliptm Date: Mon, 22 Jun 2026 14:23:20 -0500 Subject: [PATCH] Fix Fill Nodes PR follow-up edge cases --- nodes/utility/FL_InpaintCrop.py | 82 ++++++++++++++++----------------- web/FL_SystemCheck.js | 28 +++++------ 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/nodes/utility/FL_InpaintCrop.py b/nodes/utility/FL_InpaintCrop.py index 641ced2..8312808 100644 --- a/nodes/utility/FL_InpaintCrop.py +++ b/nodes/utility/FL_InpaintCrop.py @@ -152,11 +152,10 @@ class FL_InpaintCrop: # Erode inverted = 1 - dilated - eroded_inv = F.conv2d(inverted, kernel, padding=0) + eroded_inv = F.conv2d(inverted, kernel, padding=padding) closed = 1 - (eroded_inv > 0).float() - # Remove padding - closed = closed[0, 0, padding:-padding, padding:-padding] + closed = closed[0, 0] # Fill holes (find isolated regions of 0s surrounded by 1s) h, w = closed.shape @@ -192,14 +191,48 @@ class FL_InpaintCrop: if not new_seed.any(): break - # The holes are the areas that weren't reached - holes = (1 - seed) * (1 - closed) + # The holes are the areas that weren't reached + holes = (1 - seed) * (1 - closed) # Add the holes to the original mask filled = torch.clamp(closed + holes, 0, 1) return filled + def normalize_mask(self, mask, target_height, target_width, label): + if mask.dim() == 2: + mask = mask.unsqueeze(0) + elif mask.dim() == 3: + if mask.shape[0] == target_height and mask.shape[1] == target_width and mask.shape[-1] == 1: + mask = mask[..., 0].unsqueeze(0) + elif mask.dim() == 4: + if mask.shape[1] == 1: + mask = mask[:, 0] + elif mask.shape[-1] == 1: + mask = mask[..., 0] + elif mask.shape[1] <= 4 and mask.shape[-1] > 4: + mask = mask.float().mean(dim=1) + elif mask.shape[-1] <= 4: + mask = mask.float().mean(dim=-1) + else: + raise ValueError(f"Unsupported {label} shape: {mask.shape}") + else: + raise ValueError(f"Unsupported {label} shape: {mask.shape}") + + if mask.dim() != 3: + raise ValueError(f"Unsupported {label} shape after normalization: {mask.shape}") + + mask = mask.float() + if mask.shape[-2] != target_height or mask.shape[-1] != target_width: + mask = F.interpolate( + mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), + size=(target_height, target_width), + mode='nearest' + ).squeeze(1) + print(f"[FL Inpaint Crop] Auto-resized {label} to {target_width}x{target_height}") + + return torch.clamp(mask, 0.0, 1.0) + # Simplified inpaint crop - clean and predictable def inpaint_crop(self, image, mask, context_factor, target_size, resize_mode, force_square, divisible_by, invert_mask, fill_mask_holes, use_gpu, optional_context_mask=None): """ @@ -218,39 +251,7 @@ class FL_InpaintCrop: original_mask = mask original_height, original_width = image.shape[1], image.shape[2] - # Auto-resize mask to match image size - if mask.shape[-2] != image.shape[1] or mask.shape[-1] != image.shape[2]: - - # Normalize mask to NCHW - if mask.dim() == 2: - mask_nchw = mask.unsqueeze(0).unsqueeze(0) - elif mask.dim() == 3: - if mask.shape[0] == 1: - mask_nchw = mask.unsqueeze(1) - else: - mask_nchw = mask.unsqueeze(0) - elif mask.dim() == 4: - mask_nchw = mask - else: - raise ValueError(f"Unsupported mask shape: {mask.shape}") - - # 🔥 nchw to float - mask_nchw = mask_nchw.float() - - # Resize safely - mask_resized = F.interpolate( - mask_nchw, - size=(image.shape[1], image.shape[2]), - mode='nearest' - ) - - # Return to [1, H, W] - mask = mask_resized.squeeze(0).squeeze(0) - - # Clamp to valid mask range - mask = torch.clamp(mask, 0.0, 1.0) - - print(f"[FL Inpaint Crop] Auto-resized mask to {image.shape[2]}x{image.shape[1]}") + mask = self.normalize_mask(mask, original_height, original_width, "mask") # Invert mask if requested if invert_mask: @@ -283,11 +284,8 @@ class FL_InpaintCrop: # Determine context mask if optional_context_mask is None: context_mask = mask - elif optional_context_mask.shape[1] != image.shape[1] or optional_context_mask.shape[2] != image.shape[2]: - optional_context_mask = F.interpolate(optional_context_mask.unsqueeze(1), size=(image.shape[1], image.shape[2]), mode='nearest').squeeze(1) - print(f"[FL Inpaint Crop] Auto-resized context mask to {image.shape[2]}x{image.shape[1]}") - context_mask = torch.clamp(optional_context_mask + mask, 0.0, 1.0) else: + optional_context_mask = self.normalize_mask(optional_context_mask, original_height, original_width, "context mask") context_mask = torch.clamp(optional_context_mask + mask, 0.0, 1.0) # Find mask bounds diff --git a/web/FL_SystemCheck.js b/web/FL_SystemCheck.js index ccb9d38..a3a530a 100644 --- a/web/FL_SystemCheck.js +++ b/web/FL_SystemCheck.js @@ -1,8 +1,6 @@ // custom_nodes/FL_SystemCheck.js -// PATCHED VERSION (DOM widget) — compatible con el frontend nuevo de ComfyUI (>= 1.x). -// Mantiene el boton "Run System Check" y el fetch a /fl_system_info, pero renderiza la -// informacion en un DOM widget en lugar del dibujo legacy con onDrawForeground (que el -// frontend nuevo ya no pinta). Original de filliptm (Machine Delusions). +// Render system info in a DOM widget so it stays visible on the current +// ComfyUI frontend instead of relying on legacy canvas foreground drawing. import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; @@ -45,37 +43,39 @@ const colorFor = (k) => COLORS[k] || "#95a5a6"; app.registerExtension({ name: "FL.SystemCheck", async nodeCreated(node) { - if (node.comfyClass !== "FL_SystemCheck") return; + const comfyClass = (node.constructor && node.constructor.comfyClass) || node.comfyClass || ""; + if (comfyClass !== "FL_SystemCheck") return; node.color = "#2a363b"; node.bgcolor = "#4F0074"; - // Contenedor del DOM widget donde se pinta la info const container = document.createElement("div"); container.style.cssText = "display:flex;flex-direction:column;gap:6px;padding:6px;box-sizing:border-box;" + "width:100%;height:100%;overflow:auto;font-family:Arial,sans-serif;font-size:12px;color:#fff;"; const placeholder = document.createElement("div"); - placeholder.textContent = 'Pulsa "Run System Check".'; + placeholder.textContent = 'Click "Run System Check".'; placeholder.style.opacity = "0.6"; container.appendChild(placeholder); - // Boton node.addWidget("button", "Run System Check", null, () => runSystemCheck(node, container)); - // DOM widget (esto es lo que el frontend nuevo SI renderiza) - node.addDOMWidget("fl_system_info", "div", container, { serialize: false }); + node.addDOMWidget("fl_system_info", "div", container, { + getMinHeight: () => 260, + hideOnZoom: false, + serialize: false, + }); - // Tamano inicial decente - node.size = [360, 340]; + const [oldWidth, oldHeight] = node.size; + node.setSize([Math.max(oldWidth, 360), Math.max(oldHeight, 340)]); }, }); async function runSystemCheck(node, container) { container.innerHTML = ""; const loading = document.createElement("div"); - loading.textContent = "Comprobando…"; + loading.textContent = "Checking..."; loading.style.opacity = "0.7"; container.appendChild(loading); @@ -90,7 +90,7 @@ async function runSystemCheck(node, container) { container.innerHTML = ""; const err = document.createElement("div"); err.style.color = "#ff6b6b"; - err.textContent = "Error: " + e.message + " (mira la consola)."; + err.textContent = "Error: " + e.message + " (check the console)."; container.appendChild(err); console.error("[FL System Check]", e); }