Skip to content

CreateTextMask

Documentation

  • Class name: CreateTextMask
  • Category: KJNodes/text
  • Output node: False

The CreateTextMask node is designed to generate a text-based image and its corresponding mask, utilizing a variety of fonts and supporting animation through rotation parameters. It enables the creation of dynamic text visuals for various applications.

Input types

Required

  • invert
    • Determines whether the colors of the generated text image and mask should be inverted, affecting the visual contrast and style.
    • Comfy dtype: BOOLEAN
    • Python dtype: bool
  • frames
    • Specifies the number of frames to generate, allowing for the creation of animated sequences if more than one frame is used.
    • Comfy dtype: INT
    • Python dtype: int
  • text_x
    • Sets the horizontal position of the text within the image, enabling precise placement.
    • Comfy dtype: INT
    • Python dtype: int
  • text_y
    • Sets the vertical position of the text within the image, allowing for vertical alignment adjustments.
    • Comfy dtype: INT
    • Python dtype: int
  • font_size
    • Controls the size of the font used for the text, impacting the readability and visual impact of the text.
    • Comfy dtype: INT
    • Python dtype: int
  • font_color
    • Defines the color of the text, offering customization options for the text's appearance.
    • Comfy dtype: STRING
    • Python dtype: str
  • text
    • The text content to be rendered in the image, serving as the primary visual element.
    • Comfy dtype: STRING
    • Python dtype: str
  • font
    • Selects the font to be used for the text, providing a range of stylistic choices. The font list is dynamically generated based on available fonts in a specified directory.
    • Comfy dtype: COMBO[STRING]
    • Python dtype: List[str]
  • width
    • Determines the width of the generated image, defining the canvas size.
    • Comfy dtype: INT
    • Python dtype: int
  • height
    • Determines the height of the generated image, defining the canvas size.
    • Comfy dtype: INT
    • Python dtype: int
  • start_rotation
    • Sets the starting rotation angle for the text, enabling rotational animation effects when combined with end_rotation.
    • Comfy dtype: INT
    • Python dtype: int
  • end_rotation
    • Sets the ending rotation angle for the text, enabling the creation of rotational animation effects.
    • Comfy dtype: INT
    • Python dtype: int

Output types

  • image
    • Comfy dtype: IMAGE
    • The text-based image generated by the node, which can be used directly or further processed.
    • Python dtype: torch.Tensor
  • mask
    • Comfy dtype: MASK
    • The mask generated alongside the text image, useful for further image processing or effects.
    • Python dtype: torch.Tensor

Usage tips

  • Infra type: CPU
  • Common nodes: unknown

Source code

class CreateTextMask:

    RETURN_TYPES = ("IMAGE", "MASK",)
    FUNCTION = "createtextmask"
    CATEGORY = "KJNodes/text"
    DESCRIPTION = """
Creates a text image and mask.  
Looks for fonts from this folder:  
ComfyUI/custom_nodes/ComfyUI-KJNodes/fonts

If start_rotation and/or end_rotation are different values,  
creates animation between them.
"""

    @classmethod
    def INPUT_TYPES(s):
        return {
            "required": {
                 "invert": ("BOOLEAN", {"default": False}),
                 "frames": ("INT", {"default": 1,"min": 1, "max": 4096, "step": 1}),
                 "text_x": ("INT", {"default": 0,"min": 0, "max": 4096, "step": 1}),
                 "text_y": ("INT", {"default": 0,"min": 0, "max": 4096, "step": 1}),
                 "font_size": ("INT", {"default": 32,"min": 8, "max": 4096, "step": 1}),
                 "font_color": ("STRING", {"default": "white"}),
                 "text": ("STRING", {"default": "HELLO!", "multiline": True}),
                 "font": (folder_paths.get_filename_list("kjnodes_fonts"), ),
                 "width": ("INT", {"default": 512,"min": 16, "max": 4096, "step": 1}),
                 "height": ("INT", {"default": 512,"min": 16, "max": 4096, "step": 1}),
                 "start_rotation": ("INT", {"default": 0,"min": 0, "max": 359, "step": 1}),
                 "end_rotation": ("INT", {"default": 0,"min": -359, "max": 359, "step": 1}),
        },
    } 

    def createtextmask(self, frames, width, height, invert, text_x, text_y, text, font_size, font_color, font, start_rotation, end_rotation):
    # Define the number of images in the batch
        batch_size = frames
        out = []
        masks = []
        rotation = start_rotation
        if start_rotation != end_rotation:
            rotation_increment = (end_rotation - start_rotation) / (batch_size - 1)

        font_path = folder_paths.get_full_path("kjnodes_fonts", font)
        # Generate the text
        for i in range(batch_size):
            image = Image.new("RGB", (width, height), "black")
            draw = ImageDraw.Draw(image)
            font = ImageFont.truetype(font_path, font_size)

            # Split the text into words
            words = text.split()

            # Initialize variables for line creation
            lines = []
            current_line = []
            current_line_width = 0
            try: #new pillow  
                # Iterate through words to create lines
                for word in words:
                    word_width = font.getbbox(word)[2]
                    if current_line_width + word_width <= width - 2 * text_x:
                        current_line.append(word)
                        current_line_width += word_width + font.getbbox(" ")[2] # Add space width
                    else:
                        lines.append(" ".join(current_line))
                        current_line = [word]
                        current_line_width = word_width
            except: #old pillow             
                for word in words:
                    word_width = font.getsize(word)[0]
                    if current_line_width + word_width <= width - 2 * text_x:
                        current_line.append(word)
                        current_line_width += word_width + font.getsize(" ")[0] # Add space width
                    else:
                        lines.append(" ".join(current_line))
                        current_line = [word]
                        current_line_width = word_width

            # Add the last line if it's not empty
            if current_line:
                lines.append(" ".join(current_line))

            # Draw each line of text separately
            y_offset = text_y
            for line in lines:
                text_width = font.getlength(line)
                text_height = font_size
                text_center_x = text_x + text_width / 2
                text_center_y = y_offset + text_height / 2
                try:
                    draw.text((text_x, y_offset), line, font=font, fill=font_color, features=['-liga'])
                except:
                    draw.text((text_x, y_offset), line, font=font, fill=font_color)
                y_offset += text_height # Move to the next line

            if start_rotation != end_rotation:
                image = image.rotate(rotation, center=(text_center_x, text_center_y))
                rotation += rotation_increment

            image = np.array(image).astype(np.float32) / 255.0
            image = torch.from_numpy(image)[None,]
            mask = image[:, :, :, 0] 
            masks.append(mask)
            out.append(image)

        if invert:
            return (1.0 - torch.cat(out, dim=0), 1.0 - torch.cat(masks, dim=0),)
        return (torch.cat(out, dim=0),torch.cat(masks, dim=0),)