|
from PIL import Image, ImageDraw, ImageFont |
|
|
|
import folder_paths |
|
|
|
|
|
class ImageText: |
|
def __init__(self): |
|
pass |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": { |
|
"text": ("STRING", {"multiline": False}), |
|
"font": (folder_paths.get_filename_list("fonts"),), |
|
"size": ("INT", { |
|
"default": 28, |
|
"min": 1, |
|
"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 |
|
}), |
|
"margin_x": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
"margin_y": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
}, |
|
} |
|
|
|
RETURN_TYPES = ("IMAGE",) |
|
FUNCTION = "node" |
|
CATEGORY = "image/draw" |
|
|
|
def node(self, text, font, size, red, green, blue, alpha, margin_x, margin_y): |
|
outline_size = 0 |
|
outline_red = 255 |
|
outline_green = 255 |
|
outline_blue = 255 |
|
|
|
return ImageTextOutlined().node( |
|
text, |
|
font, |
|
size, |
|
red, |
|
green, |
|
blue, |
|
outline_size, |
|
outline_red, |
|
outline_green, |
|
outline_blue, |
|
alpha, |
|
margin_x, |
|
margin_y |
|
) |
|
|
|
|
|
class ImageTextOutlined: |
|
def __init__(self): |
|
pass |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": { |
|
"text": ("STRING", {"multiline": False}), |
|
"font": (folder_paths.get_filename_list("fonts"),), |
|
"size": ("INT", { |
|
"default": 28, |
|
"min": 1, |
|
"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 |
|
}), |
|
"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 |
|
}), |
|
"alpha": ("FLOAT", { |
|
"default": 1.0, |
|
"max": 1.0, |
|
"step": 0.01 |
|
}), |
|
"margin_x": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
"margin_y": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
}, |
|
} |
|
|
|
RETURN_TYPES = ("IMAGE",) |
|
FUNCTION = "node" |
|
CATEGORY = "image/draw" |
|
|
|
def node( |
|
self, text, font, size, red, green, blue, outline_size, outline_red, outline_green, outline_blue, alpha, |
|
margin_x, margin_y |
|
): |
|
font_path = folder_paths.get_full_path("fonts", font) |
|
font = ImageFont.truetype(font_path, size, encoding="unic") |
|
|
|
(left, top, right, bottom) = font.getbbox(text) |
|
|
|
canvas = Image.new("RGBA", ( |
|
right + (margin_x + outline_size) * 2, |
|
bottom - top + (margin_y + outline_size) * 2 |
|
), (0, 0, 0, 0)) |
|
|
|
draw = ImageDraw.Draw(canvas) |
|
|
|
draw.text( |
|
(margin_x + outline_size, margin_y + outline_size - top), |
|
text=text, fill=(red, green, blue, int(alpha * 255)), |
|
stroke_fill=(outline_red, outline_green, outline_blue, int(alpha * 255)), |
|
stroke_width=outline_size, font=font |
|
) |
|
|
|
return (canvas.image_to_tensor().unsqueeze(0),) |
|
|
|
|
|
class ImageTextMultiline: |
|
def __init__(self): |
|
pass |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": { |
|
"text": ("STRING", {"multiline": True}), |
|
"font": (folder_paths.get_filename_list("fonts"),), |
|
"align": (["left", "center", "right"],), |
|
"size": ("INT", { |
|
"default": 28, |
|
"min": 1, |
|
"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 |
|
}), |
|
"margin_x": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
"margin_y": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
}, |
|
} |
|
|
|
RETURN_TYPES = ("IMAGE",) |
|
FUNCTION = "node" |
|
CATEGORY = "image/draw" |
|
|
|
def node(self, text, font, align, size, red, green, blue, alpha, margin_x, margin_y): |
|
outline_size = 0 |
|
outline_red = 255 |
|
outline_green = 255 |
|
outline_blue = 255 |
|
|
|
return ImageTextMultilineOutlined().node( |
|
text, |
|
font, |
|
align, |
|
size, |
|
red, |
|
green, |
|
blue, |
|
outline_size, |
|
outline_red, |
|
outline_green, |
|
outline_blue, |
|
alpha, |
|
margin_x, |
|
margin_y |
|
) |
|
|
|
|
|
class ImageTextMultilineOutlined: |
|
def __init__(self): |
|
pass |
|
|
|
@classmethod |
|
def INPUT_TYPES(cls): |
|
return { |
|
"required": { |
|
"text": ("STRING", {"multiline": True}), |
|
"font": (folder_paths.get_filename_list("fonts"),), |
|
"align": (["left", "center", "right"],), |
|
"size": ("INT", { |
|
"default": 28, |
|
"min": 1, |
|
"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 |
|
}), |
|
"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 |
|
}), |
|
"alpha": ("FLOAT", { |
|
"default": 1.0, |
|
"max": 1.0, |
|
"step": 0.01 |
|
}), |
|
"margin_x": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
"margin_y": ("INT", { |
|
"default": 0, |
|
"step": 1 |
|
}), |
|
}, |
|
} |
|
|
|
RETURN_TYPES = ("IMAGE",) |
|
FUNCTION = "node" |
|
CATEGORY = "image/draw" |
|
|
|
def node( |
|
self, text, font, align, size, red, green, blue, outline_size, outline_red, outline_green, outline_blue, |
|
alpha, margin_x, margin_y |
|
): |
|
font_path = folder_paths.get_full_path("fonts", font) |
|
font = ImageFont.truetype(font_path, size, encoding="unic") |
|
|
|
lines = text.split('\n').__len__() |
|
(_, top, _, _) = font.getbbox(text) |
|
|
|
canvas = Image.new("RGBA", (0, 0)) |
|
draw = ImageDraw.Draw(canvas) |
|
text_size = draw.multiline_textbbox((0, 0), text, font) |
|
|
|
canvas = Image.new("RGBA", ( |
|
text_size[2] + (margin_x + outline_size) * 2, |
|
text_size[3] - top + (margin_y + (outline_size * lines)) * 2 |
|
), (0, 0, 0, 0)) |
|
|
|
draw = ImageDraw.Draw(canvas) |
|
|
|
draw.text( |
|
(margin_x + outline_size, margin_y + outline_size - top), |
|
text=text, fill=(red, green, blue, int(alpha * 255)), |
|
stroke_fill=(outline_red, outline_green, outline_blue, int(alpha * 255)), |
|
stroke_width=outline_size, font=font, align=align |
|
) |
|
|
|
return (canvas.image_to_tensor().unsqueeze(0),) |
|
|
|
|
|
NODE_CLASS_MAPPINGS = { |
|
"ImageText": ImageText, |
|
"ImageTextOutlined": ImageTextOutlined, |
|
"ImageTextMultiline": ImageTextMultiline, |
|
"ImageTextMultilineOutlined": ImageTextMultilineOutlined |
|
} |
|
|