New Node ImageBasicNode
This commit is contained in:
@@ -14,6 +14,7 @@ A comprehensive collection of useful custom nodes for ComfyUI workflows. Designe
|
||||
- **BLIP2 Image Caption**: Automatically generates a descriptive caption for an input image using Salesforce’s BLIP image captioning model. Ideal for semantic image analysis or annotation tasks.
|
||||
- **Boolean Toggle**: Returns a boolean value from a toggle input. Useful for conditionally controlling workflow branches.
|
||||
- **Concatenate and Test if Empty**: Concatenates up to four text inputs and checks whether the result is empty. Outputs both the combined string and a boolean indicating if it's empty.
|
||||
- **ImageBasicNode**: Perform basic image operations such as resizing (with optional aspect ratio preservation) and grayscale conversion. Returns the processed image along with useful metadata like width, height, aspect ratio, color mode, and format. Ideal for simple preprocessing tasks within your ComfyUI workflows.
|
||||
|
||||
*More tools coming soon! This is just the beginning of the Skycoder Tools collection.*
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from .nodes.Aspect_Ratio_and_Tile_size_calculator import NODE_CLASS_MAPPINGS as
|
||||
from .nodes.blipimagecaptioning import NODE_CLASS_MAPPINGS as BLIP_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as BLIP_DISPLAY_MAPPINGS
|
||||
from .nodes.BooleanToggleNode import NODE_CLASS_MAPPINGS as TOGGLE_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as TOGGLE_DISPLAY_MAPPINGS
|
||||
from .nodes.concatenate_and_test_if_empty import NODE_CLASS_MAPPINGS as CONCAT_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as CONCAT_DISPLAY_MAPPINGS
|
||||
from .nodes.ImageBasicNode import NODE_CLASS_MAPPINGS as BASIC_MAPPINGS
|
||||
|
||||
# Combine all Node Mappings
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
@@ -28,6 +29,8 @@ NODE_DISPLAY_NAME_MAPPINGS.update(TOGGLE_DISPLAY_MAPPINGS)
|
||||
NODE_CLASS_MAPPINGS.update(CONCAT_MAPPINGS)
|
||||
NODE_DISPLAY_NAME_MAPPINGS.update(CONCAT_DISPLAY_MAPPINGS)
|
||||
|
||||
NODE_CLASS_MAPPINGS.update(BASIC_MAPPINGS)
|
||||
|
||||
# Exportiere alle Node-Mappings für ComfyUI
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
class ImageBasicNode:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",), # ComfyUI-internes Bildobjekt
|
||||
"operation": (["no operation", "resize", "grayscale"],), # Auswahlfunktion
|
||||
"keep_aspect_ratio": ("BOOLEAN", {"default": True}),
|
||||
},
|
||||
"optional": {
|
||||
"new_width": ("INT", {"default": 256, "min": 1, "max": 4096}),
|
||||
"new_height": ("INT", {"default": 256, "min": 1, "max": 4096}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT", "INT", "FLOAT", "STRING", "STRING", "IMAGE")
|
||||
RETURN_NAMES = ("width", "height", "ratio", "mode", "format", "output_image")
|
||||
FUNCTION = "process_image"
|
||||
CATEGORY = "Beispiele/Bild"
|
||||
|
||||
def tensor2pil(self, image):
|
||||
if hasattr(image, "__len__") and not isinstance(image, (bytes, str)) and len(image) > 0:
|
||||
image = image[0]
|
||||
image = image.detach().cpu().numpy()
|
||||
image = (image*255).astype(np.uint8)
|
||||
return Image.fromarray(image)
|
||||
|
||||
def pil2tensor(self, image):
|
||||
image_np = np.array(image)
|
||||
image_np = image_np.astype(np.float32) / 255.0
|
||||
return torch.from_numpy(image_np).unsqueeze(0)
|
||||
|
||||
def bwimage(self, image):
|
||||
px=image.load()
|
||||
for y in range(image.height):
|
||||
for x in range(image.width):
|
||||
value = px[x,y]
|
||||
if isinstance(value, tuple):
|
||||
R, G, B = value[:3]
|
||||
avg = int(0.299 * R + 0.587 * G + 0.114 * B)
|
||||
px[x,y] = (avg, avg, avg)
|
||||
#print(value)
|
||||
return
|
||||
|
||||
def correctDimensions(self, width, height, ratio):
|
||||
if ratio > width / height:
|
||||
o_width = int(width)
|
||||
o_height = int(width / ratio)
|
||||
elif ratio <= width / height:
|
||||
o_width = int(height * ratio)
|
||||
o_height = int(height)
|
||||
return (o_width, o_height)
|
||||
|
||||
def process_image(self, image, operation, keep_aspect_ratio, new_width=None, new_height=None):
|
||||
# ComfyUI gibt ein numpy-Array zurück, PIL braucht das als Image
|
||||
pil_image = self.tensor2pil(image)
|
||||
|
||||
width, height = pil_image.size
|
||||
ratio = width / height
|
||||
output_image = pil_image # Default
|
||||
|
||||
if operation == "resize" and new_width and new_height:
|
||||
if keep_aspect_ratio:
|
||||
new_width, new_height = self.correctDimensions(new_width, new_height, ratio)
|
||||
|
||||
output_image = pil_image.resize((new_width, new_height))
|
||||
width, height = output_image.size
|
||||
# (Wenn nicht resized wird, bleibt Bild wie es ist)
|
||||
|
||||
elif operation == "grayscale":
|
||||
self.bwimage(output_image)
|
||||
|
||||
ratio = width / height
|
||||
mode = output_image.mode
|
||||
form = output_image.format
|
||||
|
||||
# Für ComfyUI zurück in Tensor wandeln
|
||||
img_tensor = self.pil2tensor(output_image)
|
||||
|
||||
return (width, height, ratio, mode, form, img_tensor)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ImageBasicNode": ImageBasicNode,
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "comfyui-skycoder-tools"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
description = "A collection of useful custom nodes for ComfyUI workflows"
|
||||
authors = [
|
||||
{name = "Skycoder182", email = "skycoder@example.com"}
|
||||
|
||||
Reference in New Issue
Block a user