diff --git a/README.MD b/README.MD index 96fd983..72f6078 100644 --- a/README.MD +++ b/README.MD @@ -70,6 +70,7 @@ When this error has occurred, please check the network environment. ## Update **If the dependency package error after updating, please reinstall the relevant dependency packages.
+* Add the [RGBValue](#RGBValue) node to output the color value as a single decimal value of R, G, and B. Add the [seed](#seed) node to output the seed value. The [ImageMaskScaleAs](#ImageMaskScaleAs), [ImageScaleBySspectRatio](#ImageScaleBySspectRatio), [ImageScaleBySspectRatioV2](#ImageScaleBySspectRatioV2), [ImageScaleRestore](#ImageScaleRestore), [ImageScaleRestoreV2](#ImageScaleRestoreV2) nodes increase ```width```, ```height``` output. * Commit [Levels](#Levels) node, it can achieve the same color levels adjustment function as Photoshop.[Sharp&Soft](#Sharp) add the "None" option. * Commit [BlendIfMask](#BlendIfMask) node, This node cooperates with ImgaeBlendV2 or ImageBlendAdvanceV2 to achieve the same Blend If function as Photoshop. * Commit [ColorTemperature](#ColorTemperature) and [ColorBalance](#ColorBalance) nodes, used to adjust the color temperature and color balance of the picture. @@ -546,6 +547,8 @@ Outputs: * image: The scaled image. * mask: If have mask input, the scaled mask will be output. * original_size: The original size data of the image is used for subsequent node recovery. +* width: The output image's width. +* height: The output image's height. ### ImageScaleRestoreV2 The V2 upgraded version of ImageScaleRestore. @@ -577,6 +580,8 @@ Outputs: * image: If there is an image input, the scaled image will be output. * mask: If there is a mask input, the scaled mask will be output. * original_size: The original size data of the image is used for subsequent node recovery. +* width: The output image's width. +* height: The output image's height. ### ImageScaleByAspectRatio Scale the image or mask by aspect ratio. the scaled size can be rounded to a multiple of 8 or 16, and can be scaled to the long side size. @@ -597,6 +602,13 @@ The _fill_ mode does not maintain frame ratio and fills the screen with width an * longest_side: When the scale_by_longest_side is set to True, this will be used this value to the long edge of the image. when the original_size have input, this setting will be ignored. +Outputs: +* image: If have image input, the scaled image will be output. +* mask: If have mask input, the scaled mask will be output. +* original_size: The original size data of the image is used for subsequent node recovery. +* width: The output image's width. +* height: The output image's height. + ### ImageScaleByAspectRatioV2 V2 Upgraded Version of ImageScaleByAspectRatio @@ -697,6 +709,14 @@ Node options: Output type: * value: String format. +### RGBValue +Output the color value as a single R, G, B three decimal values. Supports HEX and DEC formats for ColorPicker node output. + +![image](image/RGB_value_example.png) + +Node Options: +* color_value: Supports hexadecimal (HEX) or decimal (DEC) color values and should be of string or tuple type. Forcing in other types will result in an error. + ### GetColorTone Obtain the main color or average color from the image and output RGB values. ![image](image/get_color_tone_example.png) diff --git a/README_CN.MD b/README_CN.MD index e4f733e..68df6c5 100644 --- a/README_CN.MD +++ b/README_CN.MD @@ -70,6 +70,7 @@ git clone https://github.com/chflame163/ComfyUI_LayerStyle.git ## 更新说明 **如果本插件更新后出现依赖包错误,请重新安装相关依赖包。 + * 添加 [RGBValue](#RGBValue) 节点, 将色值输出为单独的R, G, B三个10进制数值。添加[seed](#seed) 节点,输出种子值。[ImageMaskScaleAs](#ImageMaskScaleAs), [ImageScaleBySspectRatio](#ImageScaleBySspectRatio), [ImageScaleBySspectRatioV2](#ImageScaleBySspectRatioV2), [ImageScaleRestore](#ImageScaleRestore), [ImageScaleRestoreV2](#ImageScaleRestoreV2) 节点增加```width```, ```height``` 输出。 * 添加 [Levels](#Levels) 节点, 可以实现与Photoshop相同的色阶调整功能。[Sharp&Soft](#Sharp)增加"None"选项。 * 添加 [BlendIfMask](#BlendIfMask) 节点,该节点与 ImgaeBlendV2 或者 ImageBlendAdvanceV2 配合,可以实现与Photoshop相同的混合颜色带功能。 * 添加 [ColorTemperature](#ColorTemperature) 和 [ColorBalance](#ColorBalance) 节点,用于调整图片色温和色彩平衡。 @@ -541,6 +542,8 @@ CropByMask的V2升级版。支持crop_box输入,方便裁切相同尺寸的图 * image: 缩放后的图像。 * mask: 如果有mask输入,将输出缩放后的mask。 * original_size: 图像的原始大小数据,用于后续节点进行恢复。 +* width: 输出图片的宽。 +* height: 输出图片的高。 ### ImageScaleRestoreV2 ImageScaleRestore的V2升级版。 @@ -570,6 +573,8 @@ ImageScaleRestore的V2升级版。 * image: 如果有image输入,将输出缩放后的图像。 * mask: 如果有mask输入,将输出缩放后的遮罩。 * original_size: 图像的原始大小数据,用于后续节点进行恢复。 +* width: 输出图片的宽。 +* height: 输出图片的高。 ### ImageScaleByAspectRatio @@ -592,6 +597,8 @@ ImageScaleRestore的V2升级版。 * image: 如果有image输入,将输出缩放后的图像。 * mask: 如果有mask输入,将输出缩放后的遮罩。 * original_size: 图像的原始大小数据,用于后续节点进行恢复。 +* width: 输出图片的宽。 +* height: 输出图片的高。 ### ImageScaleByAspectRatioV2 ImageScaleByAspectRatio的V2升级版 @@ -693,6 +700,15 @@ ImageScaleByAspectRatio的V2升级版 输出: * value: 字符串格式。 +### RGBValue +将色值输出为单独的R, G, B三个10进制数值。支持ColorPicker节点输出的HEX和DEC格式。 + +![image](image/RGB_value_example.png) + +节点选项说明: +* color_value: 支持十六进制(HEX)或十进制(DEC)色值,应是string或tuple类型,强行接入其他类型将导致错误。 + + ### GetColorTone 从图片中获取主颜色或平均色。 ![image](image/get_color_tone_example.png) diff --git a/image/RGB_value_example.png b/image/RGB_value_example.png new file mode 100644 index 0000000..d6590f6 Binary files /dev/null and b/image/RGB_value_example.png differ diff --git a/image/image_mask_scale_as_node.png b/image/image_mask_scale_as_node.png index 17ed6a5..dd6f5e1 100644 Binary files a/image/image_mask_scale_as_node.png and b/image/image_mask_scale_as_node.png differ diff --git a/image/image_scale_by_aspect_ratio_node.png b/image/image_scale_by_aspect_ratio_node.png index 8d9f77f..9375f9b 100644 Binary files a/image/image_scale_by_aspect_ratio_node.png and b/image/image_scale_by_aspect_ratio_node.png differ diff --git a/image/image_scale_by_aspect_ratio_v2_node.png b/image/image_scale_by_aspect_ratio_v2_node.png index 6f4a68e..33ce0c0 100644 Binary files a/image/image_scale_by_aspect_ratio_v2_node.png and b/image/image_scale_by_aspect_ratio_v2_node.png differ diff --git a/image/image_scale_restore_node.png b/image/image_scale_restore_node.png index 06bdcea..6634f4b 100644 Binary files a/image/image_scale_restore_node.png and b/image/image_scale_restore_node.png differ diff --git a/image/image_scale_restore_v2_node.png b/image/image_scale_restore_v2_node.png index 8730117..05f68d2 100644 Binary files a/image/image_scale_restore_v2_node.png and b/image/image_scale_restore_v2_node.png differ diff --git a/py/color_to_RGBvalue.py b/py/color_to_RGBvalue.py new file mode 100644 index 0000000..d1c3a02 --- /dev/null +++ b/py/color_to_RGBvalue.py @@ -0,0 +1,45 @@ +from .imagefunc import * + +NODE_NAME = 'RGB Value' +any = AnyType("*") + +class ColorValuetoRGBValue: + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(self): + + return { + "required": { + "color_value": (any, {}), + }, + "optional": { + } + } + + RETURN_TYPES = ("INT", "INT", "INT") + RETURN_NAMES = ("R", "G", "B") + FUNCTION = 'color_value_to_rgb_value' + CATEGORY = '😺dzNodes/LayerUtility' + + def color_value_to_rgb_value(self, color_value,): + R, G, B = 0, 0, 0 + if isinstance(color_value, str): + color = Hex_to_RGB(color_value) + R, G, B = color[0], color[1], color[2] + elif isinstance(color_value, tuple): + R, G, B = color_value[0], color_value[1], color_value[2] + else: + log(f"{NODE_NAME}: color_value input type must be tuple or string.", message_type="error") + + return (R, G, B,) + +NODE_CLASS_MAPPINGS = { + "LayerUtility: RGB Value": ColorValuetoRGBValue +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "LayerUtility: RGB Value": "LayerUtility: RGB Value" +} \ No newline at end of file diff --git a/py/data_nodes.py b/py/data_nodes.py index 892fe3e..3893d65 100644 --- a/py/data_nodes.py +++ b/py/data_nodes.py @@ -2,6 +2,23 @@ from .imagefunc import AnyType any = AnyType("*") +class SeedNode: + def __init__(self): + pass + @classmethod + def INPUT_TYPES(self): + return {"required": { + "seed":("INT", {"default": 0, "min": 0, "max": 99999999999999999999, "step": 1}), + },} + + RETURN_TYPES = ("INT",) + RETURN_NAMES = ("seed",) + FUNCTION = 'seed_node' + CATEGORY = '😺dzNodes/LayerUtility' + + def seed_node(self, seed): + return (seed,) + class BooleanOperator: def __init__(self): @@ -143,14 +160,14 @@ class BooleanNode: - NODE_CLASS_MAPPINGS = { "LayerUtility: BooleanOperator": BooleanOperator, "LayerUtility: NumberCalculator": NumberCalculator, "LayerUtility: TextBox": TextBoxNode, "LayerUtility: Integer": IntegerNode, "LayerUtility: Float": FloatNode, - "LayerUtility: Boolean": BooleanNode + "LayerUtility: Boolean": BooleanNode, + "LayerUtility: Seed": SeedNode } NODE_DISPLAY_NAME_MAPPINGS = { @@ -159,5 +176,6 @@ NODE_DISPLAY_NAME_MAPPINGS = { "LayerUtility: TextBox": "LayerUtility: TextBox", "LayerUtility: Integer": "LayerUtility: Integer", "LayerUtility: Float": "LayerUtility: Float", - "LayerUtility: Boolean": "LayerUtility: Boolean" + "LayerUtility: Boolean": "LayerUtility: Boolean", + "LayerUtility: Seed": "LayerUtility: Seed" } \ No newline at end of file diff --git a/py/image_mask_scale_as.py b/py/image_mask_scale_as.py index 342199b..80a52f0 100644 --- a/py/image_mask_scale_as.py +++ b/py/image_mask_scale_as.py @@ -27,8 +27,8 @@ class ImageMaskScaleAs: } } - RETURN_TYPES = ("IMAGE", "MASK", "BOX",) - RETURN_NAMES = ("image", "mask", "original_size") + RETURN_TYPES = ("IMAGE", "MASK", "BOX", "INT", "INT") + RETURN_NAMES = ("image", "mask", "original_size", "widht", "height",) FUNCTION = 'image_mask_scale_as' CATEGORY = '😺dzNodes/LayerUtility' @@ -77,16 +77,16 @@ class ImageMaskScaleAs: ret_masks.append(image2mask(_mask)) if len(ret_images) > 0 and len(ret_masks) >0: log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0), [orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0), [orig_width, orig_height],target_width, target_height,) elif len(ret_images) > 0 and len(ret_masks) == 0: log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), None, [orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), None, [orig_width, orig_height],target_width, target_height,) elif len(ret_images) == 0 and len(ret_masks) > 0: log(f"{NODE_NAME} Processed {len(ret_masks)} image(s).", message_type='finish') - return (None, torch.cat(ret_masks, dim=0), [orig_width, orig_height],) + return (None, torch.cat(ret_masks, dim=0), [orig_width, orig_height], target_width, target_height,) else: log(f"Error: {NODE_NAME} skipped, because the available image or mask is not found.", message_type='error') - return (None, None, [orig_width, orig_height],) + return (None, None, [orig_width, orig_height], 0, 0,) NODE_CLASS_MAPPINGS = { "LayerUtility: ImageMaskScaleAs": ImageMaskScaleAs diff --git a/py/image_scale_by_aspect_ratio.py b/py/image_scale_by_aspect_ratio.py index 6a2a859..81285a3 100644 --- a/py/image_scale_by_aspect_ratio.py +++ b/py/image_scale_by_aspect_ratio.py @@ -33,8 +33,8 @@ class ImageScaleByAspectRatio: } } - RETURN_TYPES = ("IMAGE", "MASK", "BOX",) - RETURN_NAMES = ("image", "mask", "original_size") + RETURN_TYPES = ("IMAGE", "MASK", "BOX", "INT", "INT",) + RETURN_NAMES = ("image", "mask", "original_size", "width", "height",) FUNCTION = 'image_scale_by_aspect_ratio' CATEGORY = '😺dzNodes/LayerUtility' @@ -65,14 +65,14 @@ class ImageScaleByAspectRatio: _width, _height = tensor2pil(orig_masks[0]).size if (orig_width > 0 and orig_width != _width) or (orig_height > 0 and orig_height != _height): log(f"Error: {NODE_NAME} skipped, because the mask is does'nt match image.", message_type='error') - return (None, None, None) + return (None, None, None, 0, 0,) elif orig_width + orig_height == 0: orig_width = _width orig_height = _height if orig_width + orig_height == 0: log(f"Error: {NODE_NAME} skipped, because the image or mask at least one must be input.", message_type='error') - return (None, None, None) + return (None, None, None, 0, 0,) if aspect_ratio == 'original': ratio = orig_width / orig_height @@ -137,16 +137,16 @@ class ImageScaleByAspectRatio: ret_masks.append(image2mask(_mask)) if len(ret_images) > 0 and len(ret_masks) >0: log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0),[orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0),[orig_width, orig_height], target_width, target_height,) elif len(ret_images) > 0 and len(ret_masks) == 0: log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), None,[orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), None,[orig_width, orig_height], target_width, target_height,) elif len(ret_images) == 0 and len(ret_masks) > 0: log(f"{NODE_NAME} Processed {len(ret_masks)} image(s).", message_type='finish') - return (None, torch.cat(ret_masks, dim=0),[orig_width, orig_height],) + return (None, torch.cat(ret_masks, dim=0),[orig_width, orig_height], target_width, target_height,) else: log(f"Error: {NODE_NAME} skipped, because the available image or mask is not found.", message_type='error') - return (None, None, None) + return (None, None, None, 0, 0,) NODE_CLASS_MAPPINGS = { "LayerUtility: ImageScaleByAspectRatio": ImageScaleByAspectRatio diff --git a/py/image_scale_by_aspect_ratio_v2.py b/py/image_scale_by_aspect_ratio_v2.py index 096ed82..90b233b 100644 --- a/py/image_scale_by_aspect_ratio_v2.py +++ b/py/image_scale_by_aspect_ratio_v2.py @@ -33,8 +33,8 @@ class ImageScaleByAspectRatioV2: } } - RETURN_TYPES = ("IMAGE", "MASK", "BOX",) - RETURN_NAMES = ("image", "mask", "original_size") + RETURN_TYPES = ("IMAGE", "MASK", "BOX", "INT", "INT",) + RETURN_NAMES = ("image", "mask", "original_size", "width", "height",) FUNCTION = 'image_scale_by_aspect_ratio' CATEGORY = '😺dzNodes/LayerUtility' @@ -65,14 +65,14 @@ class ImageScaleByAspectRatioV2: _width, _height = tensor2pil(orig_masks[0]).size if (orig_width > 0 and orig_width != _width) or (orig_height > 0 and orig_height != _height): log(f"Error: {NODE_NAME} skipped, because the mask is does'nt match image.", message_type='error') - return (None, None, None) + return (None, None, None, 0, 0,) elif orig_width + orig_height == 0: orig_width = _width orig_height = _height if orig_width + orig_height == 0: log(f"Error: {NODE_NAME} skipped, because the image or mask at least one must be input.", message_type='error') - return (None, None, None) + return (None, None, None, 0, 0,) if aspect_ratio == 'original': ratio = orig_width / orig_height @@ -136,16 +136,16 @@ class ImageScaleByAspectRatioV2: ret_masks.append(image2mask(_mask)) if len(ret_images) > 0 and len(ret_masks) >0: log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0),[orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0),[orig_width, orig_height], target_width, target_height,) elif len(ret_images) > 0 and len(ret_masks) == 0: log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), None, [orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), None, [orig_width, orig_height], target_width, target_height,) elif len(ret_images) == 0 and len(ret_masks) > 0: log(f"{NODE_NAME} Processed {len(ret_masks)} image(s).", message_type='finish') - return (None, torch.cat(ret_masks, dim=0), [orig_width, orig_height],) + return (None, torch.cat(ret_masks, dim=0), [orig_width, orig_height], target_width, target_height,) else: log(f"Error: {NODE_NAME} skipped, because the available image or mask is not found.", message_type='error') - return (None, None, None) + return (None, None, None, 0, 0,) NODE_CLASS_MAPPINGS = { "LayerUtility: ImageScaleByAspectRatio V2": ImageScaleByAspectRatioV2 diff --git a/py/image_scale_restore.py b/py/image_scale_restore.py index 28df761..5d8a186 100644 --- a/py/image_scale_restore.py +++ b/py/image_scale_restore.py @@ -24,8 +24,8 @@ class ImageScaleRestore: } } - RETURN_TYPES = ("IMAGE", "MASK", "BOX",) - RETURN_NAMES = ("image", "mask", "original_size") + RETURN_TYPES = ("IMAGE", "MASK", "BOX", "INT", "INT") + RETURN_NAMES = ("image", "mask", "original_size", "width", "height",) FUNCTION = 'image_scale_restore' CATEGORY = '😺dzNodes/LayerUtility' @@ -98,7 +98,7 @@ class ImageScaleRestore: ret_masks.append(image2mask(ret_mask)) log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0), [orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0), [orig_width, orig_height], target_width, target_height,) NODE_CLASS_MAPPINGS = { diff --git a/py/image_scale_restore_v2.py b/py/image_scale_restore_v2.py index cf8f831..ed91118 100644 --- a/py/image_scale_restore_v2.py +++ b/py/image_scale_restore_v2.py @@ -25,8 +25,8 @@ class ImageScaleRestoreV2: } } - RETURN_TYPES = ("IMAGE", "MASK", "BOX",) - RETURN_NAMES = ("image", "mask", "original_size") + RETURN_TYPES = ("IMAGE", "MASK", "BOX", "INT", "INT") + RETURN_NAMES = ("image", "mask", "original_size", "width", "height",) FUNCTION = 'image_scale_restore' CATEGORY = '😺dzNodes/LayerUtility' @@ -106,7 +106,7 @@ class ImageScaleRestoreV2: ret_masks.append(image2mask(ret_mask)) log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') - return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0), [orig_width, orig_height],) + return (torch.cat(ret_images, dim=0), torch.cat(ret_masks, dim=0), [orig_width, orig_height], target_width, target_height,) NODE_CLASS_MAPPINGS = { diff --git a/py/imagefunc.py b/py/imagefunc.py index 18eb987..1a11b13 100644 --- a/py/imagefunc.py +++ b/py/imagefunc.py @@ -1,7 +1,6 @@ """Image process functions for ComfyUI nodes by chflame https://github.com/chflame163 -""" -""" + @author: chflame @title: LayerStyle @nickname: LayerStyle