diff --git a/box_reinsert_node.py b/box_reinsert_node.py index 32ab745..fecf8ad 100644 --- a/box_reinsert_node.py +++ b/box_reinsert_node.py @@ -87,11 +87,22 @@ class BoxReinsertNode: y1 = box_meta.get("y1", 0) y2 = box_meta.get("y2", 0) + # Applica fattore di scala se la preview era stata scalata + display_scale_factor = box_meta.get("displayScaleFactor", 1.0) + if display_scale_factor and display_scale_factor != 1.0: + # Se le coordinate sono state prese da una preview scalata, + # dividi per il fattore di scala per ottenere le coordinate originali + x1 = x1 / display_scale_factor + x2 = x2 / display_scale_factor + y1 = y1 / display_scale_factor + y2 = y2 / display_scale_factor + print(f"[BoxReinsertNode] Scale factor detected: {display_scale_factor}x. Adjusted coordinates.") + # Normalizza coordinate (assicura che x1 < x2, y1 < y2) - box_x_start = min(x1, x2) - box_x_end = max(x1, x2) - box_y_start = min(y1, y2) - box_y_end = max(y1, y2) + box_x_start = int(round(min(x1, x2))) + box_x_end = int(round(max(x1, x2))) + box_y_start = int(round(min(y1, y2))) + box_y_end = int(round(max(y1, y2))) crop_width = box_x_end - box_x_start crop_height = box_y_end - box_y_start diff --git a/pyproject.toml b/pyproject.toml index cdb818b..b32c54a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "ComfyUI-BoxBox" description = "BoxBox is a lightweight ComfyUI extension for visualizing image boxes and controlling regions interactively inside the node interface." -version = "1.0.0" +version = "1.0.1" license = {file = "LICENSE"} # classifiers = [ # # For OS-independent nodes (works on all operating systems) diff --git a/region_crop_node.py b/region_crop_node.py index 906c1ee..c4dc643 100644 --- a/region_crop_node.py +++ b/region_crop_node.py @@ -73,6 +73,17 @@ class RegionCropNode: else: raise ValueError("No region coordinates provided in metadata") + # Estrai il fattore di scala se la preview era stata scalata + display_scale_factor = metadata.get("displayScaleFactor", 1.0) + if display_scale_factor and display_scale_factor != 1.0: + # Se le coordinate sono state prese da una preview scalata, + # dividi per il fattore di scala per ottenere le coordinate originali + x1 = x1 / display_scale_factor + x2 = x2 / display_scale_factor + y1 = y1 / display_scale_factor + y2 = y2 / display_scale_factor + print(f"[BoxCrop] Scale factor detected: {display_scale_factor}x. Adjusted coordinates.") + # Assicura che le coordinate siano integer x1 = int(round(x1)) x2 = int(round(x2)) diff --git a/region_selector_node.py b/region_selector_node.py index c0e7073..22c5eaf 100644 --- a/region_selector_node.py +++ b/region_selector_node.py @@ -1,45 +1,29 @@ """ -Region Selector Node - Nodo per selezionare regioni di immagini con interfaccia popup +Region Selector Node - con endpoint di ridimensionamento lato backend. +Riduce automaticamente le immagini oltre 1024px quando viene aperta +l'interfaccia "Select Box", salvandole in /temp/. """ +import os import json +from PIL import Image +import folder_paths +import server class RegionSelectorNode: - """ - Nodo che permette di selezionare una regione rettangolare su un'immagine - tramite un'interfaccia interattiva in popup. - - Outputs: - - IMAGE: L'immagine passata - - STRING: Metadata JSON con coordinate della regione selezionata - """ - def __init__(self): - # Metadata di default con coordinate x1, x2, y1, y2 (lati, non posizione+dimensioni) self.last_metadata = json.dumps({ - "x1": 0, - "y1": 0, - "x2": 0, - "y2": 0, - "zoom": 1, - "borderWidth": 0, - "borderPosition": "inside", - "selected": False + "x1": 0, "y1": 0, "x2": 0, "y2": 0, + "zoom": 1, "borderWidth": 0, + "borderPosition": "inside", "selected": False }) @classmethod def INPUT_TYPES(cls): return { - "required": { - "image": ("IMAGE",), - }, - "optional": { - "region_metadata": ("STRING", { - "default": "{}", - "multiline": True, - }), - } + "required": {"image": ("IMAGE",)}, + "optional": {"region_metadata": ("STRING", {"default": "{}", "multiline": True})} } RETURN_TYPES = ("IMAGE", "STRING") @@ -49,27 +33,47 @@ class RegionSelectorNode: OUTPUT_NODE = True def process_region_selection(self, image, region_metadata="{}"): - """ - Processa l'immagine e ritorna l'immagine + metadata della regione selezionata. - - Args: - image: Tensor immagine (B, H, W, C) - region_metadata: JSON string con coordinate della regione (x1, x2, y1, y2) - - Returns: - (image, region_metadata_json): Immagine originale e metadata JSON - """ - - # Usa il metadata fornito, o l'ultimo salvato se vuoto - if region_metadata and region_metadata.strip() and region_metadata != "{}": - metadata_to_return = region_metadata + if region_metadata.strip() and region_metadata != "{}": self.last_metadata = region_metadata - else: - # Se nessun metadata รจ stato fornito, usa l'ultimo salvato - metadata_to_return = self.last_metadata + return (image, self.last_metadata) - print(f"[RegionSelectorNode] Processing selection, metadata: {metadata_to_return}") - return (image, metadata_to_return) + +def scale_image_if_needed(filename, max_size=1024): + input_path = folder_paths.get_input_directory() + full_path = os.path.join(input_path, filename) + if not os.path.exists(full_path): + return {"error": "file non trovato"} + + with Image.open(full_path) as im: + w, h = im.size + if w <= max_size and h <= max_size: + return {"scaled": False, "path": f"view?filename={filename}&type=input"} + + scale_factor = min(max_size / w, max_size / h) + new_size = (int(w * scale_factor), int(h * scale_factor)) + im_resized = im.resize(new_size, Image.Resampling.LANCZOS) + + os.makedirs("temp", exist_ok=True) + scaled_name = f"scaled_{filename}" + scaled_path = os.path.join("temp", scaled_name) + im_resized.save(scaled_path) + print(f"[RegionSelector] Immagine scalata {w}x{h} -> {new_size[0]}x{new_size[1]}") + + return {"scaled": True, "path": f"view?filename={scaled_name}&type=temp", "scale": scale_factor} + + +@server.PromptServer.instance.routes.post("/region_selector/scale") +async def scale_image_endpoint(request): + try: + data = await request.json() + filename = data.get("filename") + if not filename: + return {"error": "filename mancante"} + result = scale_image_if_needed(filename) + return result + except Exception as e: + print(f"[RegionSelector] Errore endpoint scale: {e}") + return {"error": str(e)} NODE_CLASS_MAPPINGS = {"BoxSelector": RegionSelectorNode}