From d8e13e92ac64389668a2265025c1b46f8532efe1 Mon Sep 17 00:00:00 2001 From: Nourepide Date: Wed, 7 Jun 2023 08:36:06 +0300 Subject: [PATCH] Add ByContainer version of ImageDraw nodes --- README.MD | 36 +- modules/ImageDraw.py | 883 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 869 insertions(+), 50 deletions(-) diff --git a/README.MD b/README.MD index 541a67c..0e04fc3 100644 --- a/README.MD +++ b/README.MD @@ -450,24 +450,6 @@ You also can change the fonts folder in config. -### Polygon -![image_draw_polygon](images/image_draw_polygon.png) -> Draws a polygon. - -
- Params: - -* size `[1 - *]` - Size of image. -* sides `[3 - *]` - Sides of polygon. -* rotation `[0 - 360]` - Apply an arbitrary rotation to the polygon in degree. -* outline_size `[0 - *]` - Outline size in PX. -* outline_[red, green, blue] `[0 - 255]` - Color of the outline in RGB. -* outline_alpha `[0.0 - 1.0]` - Transparency of the outline. -* fill_[red, green, blue] `[0 - 255]` - Color of the fill in RGB. -* fill_alpha `[0.0 - 1.0]` - Transparency of the fill. - -
- ### Rectangle ![image_draw_rectangle](images/image_draw_rectangle.png) > Draws a rectangle. @@ -506,6 +488,24 @@ You also can change the fonts folder in config. +### Polygon +![image_draw_polygon](images/image_draw_polygon.png) +> Draws a polygon. + +
+ Params: + +* size `[1 - *]` - Size of image. +* sides `[3 - *]` - Sides of polygon. +* rotation `[0 - 360]` - Apply an arbitrary rotation to the polygon in degree. +* outline_size `[0 - *]` - Outline size in PX. +* outline_[red, green, blue] `[0 - 255]` - Color of the outline in RGB. +* outline_alpha `[0.0 - 1.0]` - Transparency of the outline. +* fill_[red, green, blue] `[0 - 255]` - Color of the fill in RGB. +* fill_alpha `[0.0 - 1.0]` - Transparency of the fill. + +
+ --- diff --git a/modules/ImageDraw.py b/modules/ImageDraw.py index 195b3dc..7e3cb39 100644 --- a/modules/ImageDraw.py +++ b/modules/ImageDraw.py @@ -105,6 +105,103 @@ class ImageDrawArc: return (canvas.image_to_tensor().unsqueeze(0),) +class ImageDrawArcByContainer: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "container": ("IMAGE",), + "size": ("INT", { + "default": 1, + "min": 1, + "step": 1 + }), + "start_x": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "start_y": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "end_x": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "end_y": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "start": ("INT", { + "default": 0, + "max": 360, + "step": 1 + }), + "end": ("INT", { + "default": 180, + "max": 360, + "step": 1 + }), + "red": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "green": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "blue": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "SSAA": ("INT", { + "default": 8, + "min": 1, + "max": 16, + "step": 1 + }), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "image_draw_arc_by_container" + CATEGORY = "image/draw" + + # noinspection PyPep8Naming + def image_draw_arc_by_container(self, container, size, start_x, start_y, end_x, end_y, start, end, red, green, blue, alpha, SSAA): + return ImageDrawArc().image_draw_arc( + container[0, :, :, 0].shape[1], + container[0, :, :, 0].shape[0], + size, + start_x, + start_y, + end_x, + end_y, + start, + end, + red, + green, + blue, + alpha, + SSAA + ) + + class ImageDrawChord: def __init__(self): pass @@ -209,6 +306,103 @@ class ImageDrawChord: return (canvas.image_to_tensor().unsqueeze(0),) +class ImageDrawChordByContainer: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "container": ("IMAGE",), + "size": ("INT", { + "default": 1, + "min": 1, + "step": 1 + }), + "start_x": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "start_y": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "end_x": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "end_y": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "start": ("INT", { + "default": 0, + "max": 360, + "step": 1 + }), + "end": ("INT", { + "default": 180, + "max": 360, + "step": 1 + }), + "red": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "green": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "blue": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "SSAA": ("INT", { + "default": 8, + "min": 1, + "max": 16, + "step": 1 + }), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "image_draw_chord_by_container" + CATEGORY = "image/draw" + + # noinspection PyPep8Naming + def image_draw_chord_by_container(self, container, size, start_x, start_y, end_x, end_y, start, end, red, green, blue, alpha, SSAA): + return ImageDrawChord().image_draw_chord( + container[0, :, :, 0].shape[1], + container[0, :, :, 0].shape[0], + size, + start_x, + start_y, + end_x, + end_y, + start, + end, + red, + green, + blue, + alpha, + SSAA + ) + + class ImageDrawEllipse: def __init__(self): pass @@ -342,6 +536,131 @@ class ImageDrawEllipse: return (canvas.image_to_tensor().unsqueeze(0),) +class ImageDrawEllipseByContainer: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "container": ("IMAGE",), + "start_x": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "start_y": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "end_x": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "end_y": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "outline_size": ("INT", { + "default": 1, + "step": 1 + }), + "outline_red": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_green": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_blue": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "fill_red": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_green": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_blue": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "SSAA": ("INT", { + "default": 8, + "min": 1, + "max": 16, + "step": 1 + }), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "image_draw_ellipse_by_container" + CATEGORY = "image/draw" + + # noinspection PyPep8Naming + def image_draw_ellipse_by_container( + self, + container, + start_x, + start_y, + end_x, + end_y, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + SSAA + ): + return ImageDrawEllipse().image_draw_ellipse( + container[0, :, :, 0].shape[1], + container[0, :, :, 0].shape[0], + start_x, + start_y, + end_x, + end_y, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + SSAA + ) + + class ImageDrawLine: def __init__(self): pass @@ -436,6 +755,91 @@ class ImageDrawLine: return (canvas.image_to_tensor().unsqueeze(0),) +class ImageDrawLineByContainer: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "container": ("IMAGE",), + "size": ("INT", { + "default": 1, + "min": 1, + "step": 1 + }), + "start_x": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "start_y": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 + }), + "end_x": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "end_y": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "red": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "green": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "blue": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "SSAA": ("INT", { + "default": 8, + "min": 1, + "max": 16, + "step": 1 + }), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "image_draw_line_by_container" + CATEGORY = "image/draw" + + # noinspection PyPep8Naming + def image_draw_line_by_container(self, container, size, start_x, start_y, end_x, end_y, red, green, blue, alpha, SSAA): + return ImageDrawLine().image_draw_line( + container[0, :, :, 0].shape[1], + container[0, :, :, 0].shape[0], + size, + start_x, + start_y, + end_x, + end_y, + red, + green, + blue, + alpha, + SSAA + ) + + class ImageDrawPieslice: def __init__(self): pass @@ -582,7 +986,7 @@ class ImageDrawPieslice: return (canvas.image_to_tensor().unsqueeze(0),) -class ImageDrawPolygon: +class ImageDrawPiesliceByContainer: def __init__(self): pass @@ -590,21 +994,37 @@ class ImageDrawPolygon: def INPUT_TYPES(cls): return { "required": { - "size": ("INT", { - "default": 256, - "min": 1, - "step": 1 + "container": ("IMAGE",), + "start_x": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 }), - "sides": ("INT", { - "default": 5, - "min": 3, - "step": 1 + "start_y": ("FLOAT", { + "default": 0.0, + "max": 1.0, + "step": 0.01 }), - "rotation": ("INT", { + "end_x": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "end_y": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "start": ("INT", { "default": 0, "max": 360, "step": 1 }), + "end": ("INT", { + "default": 240, + "max": 360, + "step": 1 + }), "outline_size": ("INT", { "default": 1, "step": 1 @@ -659,15 +1079,19 @@ class ImageDrawPolygon: } RETURN_TYPES = ("IMAGE",) - FUNCTION = "image_draw_polygon" + FUNCTION = "image_draw_pieslice_by_container" CATEGORY = "image/draw" - # noinspection PyPep8Naming, PyUnresolvedReferences - def image_draw_polygon( + # noinspection PyPep8Naming + def image_draw_pieslice_by_container( self, - size, - sides, - rotation, + container, + start_x, + start_y, + end_x, + end_y, + start, + end, outline_size, outline_red, outline_green, @@ -679,22 +1103,27 @@ class ImageDrawPolygon: fill_alpha, SSAA ): - canvas = Image.new("RGBA", (size * SSAA, size * SSAA), (0, 0, 0, 0)) - - draw = ImageDraw.Draw(canvas) - draw.regular_polygon( - (size * SSAA / 2, size * SSAA / 2, size * SSAA / 2), - sides, rotation, - (fill_red, fill_green, fill_blue, int(fill_alpha * 255)), - (outline_red, outline_green, outline_blue, int(outline_alpha * 255)), - # TODO: Uncomment after the release of PIL 9.6.0 - # outline_size * SSAA + return ImageDrawPieslice().image_draw_pieslice( + container[0, :, :, 0].shape[1], + container[0, :, :, 0].shape[0], + start_x, + start_y, + end_x, + end_y, + start, + end, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + SSAA ) - canvas = canvas.resize((size, size), Image.ANTIALIAS) - - return (canvas.image_to_tensor().unsqueeze(0),) - class ImageDrawRectangle: def __init__(self): @@ -829,6 +1258,131 @@ class ImageDrawRectangle: return (canvas.image_to_tensor().unsqueeze(0),) +class ImageDrawRectangleByContainer: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "container": ("IMAGE",), + "start_x": ("FLOAT", { + "default": 0.1, + "max": 1.0, + "step": 0.01 + }), + "start_y": ("FLOAT", { + "default": 0.2, + "max": 1.0, + "step": 0.01 + }), + "end_x": ("FLOAT", { + "default": 0.9, + "max": 1.0, + "step": 0.01 + }), + "end_y": ("FLOAT", { + "default": 0.8, + "max": 1.0, + "step": 0.01 + }), + "outline_size": ("INT", { + "default": 1, + "step": 1 + }), + "outline_red": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_green": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_blue": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "fill_red": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_green": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_blue": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "SSAA": ("INT", { + "default": 8, + "min": 1, + "max": 16, + "step": 1 + }), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "image_draw_rectangle_by_container" + CATEGORY = "image/draw" + + # noinspection PyPep8Naming + def image_draw_rectangle_by_container( + self, + container, + start_x, + start_y, + end_x, + end_y, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + SSAA + ): + return ImageDrawRectangle().image_draw_rectangle( + container[0, :, :, 0].shape[1], + container[0, :, :, 0].shape[0], + start_x, + start_y, + end_x, + end_y, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + SSAA + ) + + class ImageDrawRectangleRounded: def __init__(self): pass @@ -983,13 +1537,278 @@ class ImageDrawRectangleRounded: return (canvas.image_to_tensor().unsqueeze(0),) +class ImageDrawRectangleRoundedByContainer: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "container": ("IMAGE",), + "start_x": ("FLOAT", { + "default": 0.1, + "max": 1.0, + "step": 0.01 + }), + "start_y": ("FLOAT", { + "default": 0.2, + "max": 1.0, + "step": 0.01 + }), + "end_x": ("FLOAT", { + "default": 0.9, + "max": 1.0, + "step": 0.01 + }), + "end_y": ("FLOAT", { + "default": 0.8, + "max": 1.0, + "step": 0.01 + }), + "radius": ("INT", { + "default": 180, + "max": 360, + "step": 1 + }), + "outline_size": ("INT", { + "default": 1, + "step": 1 + }), + "outline_red": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_green": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_blue": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "fill_red": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_green": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_blue": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "top_left_corner": (["true", "false"],), + "top_right_corner": (["true", "false"],), + "bottom_right_corner": (["true", "false"],), + "bottom_left_corner": (["true", "false"],), + "SSAA": ("INT", { + "default": 8, + "min": 1, + "max": 16, + "step": 1 + }), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "image_draw_rounded_by_container" + CATEGORY = "image/draw" + + # noinspection PyPep8Naming, PyUnresolvedReferences, PyArgumentList + def image_draw_rounded_by_container( + self, + container, + start_x, + start_y, + end_x, + end_y, + radius, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + top_left_corner, + top_right_corner, + bottom_right_corner, + bottom_left_corner, + SSAA + ): + return ImageDrawRectangleRounded().image_draw_rounded( + container[0, :, :, 0].shape[1], + container[0, :, :, 0].shape[0], + start_x, + start_y, + end_x, + end_y, + radius, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + top_left_corner, + top_right_corner, + bottom_right_corner, + bottom_left_corner, + SSAA + ) + + +class ImageDrawPolygon: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "size": ("INT", { + "default": 256, + "min": 1, + "step": 1 + }), + "sides": ("INT", { + "default": 5, + "min": 3, + "step": 1 + }), + "rotation": ("INT", { + "default": 0, + "max": 360, + "step": 1 + }), + "outline_size": ("INT", { + "default": 1, + "step": 1 + }), + "outline_red": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_green": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_blue": ("INT", { + "default": 0, + "max": 255, + "step": 1 + }), + "outline_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "fill_red": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_green": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_blue": ("INT", { + "default": 255, + "max": 255, + "step": 1 + }), + "fill_alpha": ("FLOAT", { + "default": 1.0, + "max": 1.0, + "step": 0.01 + }), + "SSAA": ("INT", { + "default": 8, + "min": 1, + "max": 16, + "step": 1 + }), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "image_draw_polygon" + CATEGORY = "image/draw" + + # noinspection PyPep8Naming, PyUnresolvedReferences + def image_draw_polygon( + self, + size, + sides, + rotation, + outline_size, + outline_red, + outline_green, + outline_blue, + outline_alpha, + fill_red, + fill_green, + fill_blue, + fill_alpha, + SSAA + ): + canvas = Image.new("RGBA", (size * SSAA, size * SSAA), (0, 0, 0, 0)) + + draw = ImageDraw.Draw(canvas) + draw.regular_polygon( + (size * SSAA / 2, size * SSAA / 2, size * SSAA / 2), + sides, rotation, + (fill_red, fill_green, fill_blue, int(fill_alpha * 255)), + (outline_red, outline_green, outline_blue, int(outline_alpha * 255)), + # TODO: Uncomment after the release of PIL 9.6.0 + # outline_size * SSAA + ) + + canvas = canvas.resize((size, size), Image.ANTIALIAS) + + return (canvas.image_to_tensor().unsqueeze(0),) + + NODE_CLASS_MAPPINGS = { "ImageDrawArc": ImageDrawArc, + "ImageDrawArcByContainer": ImageDrawArcByContainer, "ImageDrawChord": ImageDrawChord, + "ImageDrawChordByContainer": ImageDrawChordByContainer, "ImageDrawEllipse": ImageDrawEllipse, + "ImageDrawEllipseByContainer": ImageDrawEllipseByContainer, "ImageDrawLine": ImageDrawLine, + "ImageDrawLineByContainer": ImageDrawLineByContainer, "ImageDrawPieslice": ImageDrawPieslice, - "ImageDrawPolygon": ImageDrawPolygon, + "ImageDrawPiesliceByContainer": ImageDrawPiesliceByContainer, "ImageDrawRectangle": ImageDrawRectangle, - "ImageDrawRectangleRounded": ImageDrawRectangleRounded + "ImageDrawRectangleByContainer": ImageDrawRectangleByContainer, + "ImageDrawRectangleRounded": ImageDrawRectangleRounded, + "ImageDrawRectangleRoundedByContainer": ImageDrawRectangleRoundedByContainer, + "ImageDrawPolygon": ImageDrawPolygon, }