mirror of
https://git.datalinker.icu/kijai/ComfyUI-KJNodes.git
synced 2026-06-08 15:57:51 +08:00
Add CreateTextOnPath -node
This commit is contained in:
parent
d12a011943
commit
855f9993b9
@ -97,6 +97,7 @@ NODE_CONFIG = {
|
|||||||
#curve nodes
|
#curve nodes
|
||||||
"SplineEditor": {"class": SplineEditor, "name": "Spline Editor"},
|
"SplineEditor": {"class": SplineEditor, "name": "Spline Editor"},
|
||||||
"CreateShapeMaskOnPath": {"class": CreateShapeMaskOnPath, "name": "Create Shape Mask On Path"},
|
"CreateShapeMaskOnPath": {"class": CreateShapeMaskOnPath, "name": "Create Shape Mask On Path"},
|
||||||
|
"CreateTextOnPath": {"class": CreateTextOnPath, "name": "Create Text On Path"},
|
||||||
"WeightScheduleExtend": {"class": WeightScheduleExtend, "name": "Weight Schedule Extend"},
|
"WeightScheduleExtend": {"class": WeightScheduleExtend, "name": "Weight Schedule Extend"},
|
||||||
"MaskOrImageToWeight": {"class": MaskOrImageToWeight, "name": "Mask Or Image To Weight"},
|
"MaskOrImageToWeight": {"class": MaskOrImageToWeight, "name": "Mask Or Image To Weight"},
|
||||||
"WeightScheduleConvert": {"class": WeightScheduleConvert, "name": "Weight Schedule Convert"},
|
"WeightScheduleConvert": {"class": WeightScheduleConvert, "name": "Weight Schedule Convert"},
|
||||||
|
|||||||
@ -232,7 +232,6 @@ class CreateShapeMaskOnPath:
|
|||||||
DESCRIPTION = """
|
DESCRIPTION = """
|
||||||
Creates a mask or batch of masks with the specified shape.
|
Creates a mask or batch of masks with the specified shape.
|
||||||
Locations are center locations.
|
Locations are center locations.
|
||||||
Grow value is the amount to grow the shape on each frame, creating animated masks.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -303,6 +302,93 @@ Grow value is the amount to grow the shape on each frame, creating animated mask
|
|||||||
outstack = torch.cat(out, dim=0)
|
outstack = torch.cat(out, dim=0)
|
||||||
return (outstack, 1.0 - outstack,)
|
return (outstack, 1.0 - outstack,)
|
||||||
|
|
||||||
|
class CreateTextOnPath:
|
||||||
|
|
||||||
|
RETURN_TYPES = ("IMAGE", "MASK", "MASK",)
|
||||||
|
RETURN_NAMES = ("image", "mask", "mask_inverted",)
|
||||||
|
FUNCTION = "createtextmask"
|
||||||
|
CATEGORY = "KJNodes/masking/generate"
|
||||||
|
DESCRIPTION = """
|
||||||
|
Creates a mask or batch of masks with the specified text.
|
||||||
|
Locations are center locations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"coordinates": ("STRING", {"forceInput": True}),
|
||||||
|
"text": ("STRING", {"default": 'text', "multiline": True}),
|
||||||
|
"frame_width": ("INT", {"default": 512,"min": 16, "max": 4096, "step": 1}),
|
||||||
|
"frame_height": ("INT", {"default": 512,"min": 16, "max": 4096, "step": 1}),
|
||||||
|
"font": (folder_paths.get_filename_list("kjnodes_fonts"), ),
|
||||||
|
"font_size": ("INT", {"default": 42}),
|
||||||
|
"alignment": (
|
||||||
|
[ 'left',
|
||||||
|
'center',
|
||||||
|
'right'
|
||||||
|
],
|
||||||
|
{"default": 'center'}
|
||||||
|
),
|
||||||
|
"text_color": ("STRING", {"default": 'white'}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"size_multiplier": ("FLOAT", {"default": [1.0], "forceInput": True}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def createtextmask(self, coordinates, frame_width, frame_height, font, font_size, text, text_color, alignment, size_multiplier=[1.0]):
|
||||||
|
coordinates = coordinates.replace("'", '"')
|
||||||
|
coordinates = json.loads(coordinates)
|
||||||
|
|
||||||
|
batch_size = len(coordinates)
|
||||||
|
mask_list = []
|
||||||
|
image_list = []
|
||||||
|
color = text_color
|
||||||
|
font_path = folder_paths.get_full_path("kjnodes_fonts", font)
|
||||||
|
|
||||||
|
if len(size_multiplier) != batch_size:
|
||||||
|
size_multiplier = size_multiplier * (batch_size // len(size_multiplier)) + size_multiplier[:batch_size % len(size_multiplier)]
|
||||||
|
|
||||||
|
for i, coord in enumerate(coordinates):
|
||||||
|
image = Image.new("RGB", (frame_width, frame_height), "black")
|
||||||
|
draw = ImageDraw.Draw(image)
|
||||||
|
lines = text.split('\n') # Split the text into lines
|
||||||
|
# Apply the size multiplier to the font size for this iteration
|
||||||
|
current_font_size = int(font_size * size_multiplier[i])
|
||||||
|
current_font = ImageFont.truetype(font_path, current_font_size)
|
||||||
|
line_heights = [current_font.getbbox(line)[3] for line in lines] # List of line heights
|
||||||
|
total_text_height = sum(line_heights) # Total height of text block
|
||||||
|
|
||||||
|
# Calculate the starting Y position to center the block of text
|
||||||
|
start_y = coord['y'] - total_text_height // 2
|
||||||
|
for j, line in enumerate(lines):
|
||||||
|
text_width, text_height = current_font.getbbox(line)[2], line_heights[j]
|
||||||
|
if alignment == 'left':
|
||||||
|
location_x = coord['x']
|
||||||
|
elif alignment == 'center':
|
||||||
|
location_x = int(coord['x'] - text_width // 2)
|
||||||
|
elif alignment == 'right':
|
||||||
|
location_x = int(coord['x'] - text_width)
|
||||||
|
|
||||||
|
location_y = int(start_y + sum(line_heights[:j]))
|
||||||
|
text_position = (location_x, location_y)
|
||||||
|
# Draw the text
|
||||||
|
try:
|
||||||
|
draw.text(text_position, line, fill=color, font=current_font, features=['-liga'])
|
||||||
|
except:
|
||||||
|
draw.text(text_position, line, fill=color, font=current_font)
|
||||||
|
|
||||||
|
image = pil2tensor(image)
|
||||||
|
non_black_pixels = (image > 0).any(dim=-1)
|
||||||
|
mask = non_black_pixels.to(image.dtype)
|
||||||
|
mask_list.append(mask)
|
||||||
|
image_list.append(image)
|
||||||
|
|
||||||
|
out_images = torch.cat(image_list, dim=0).cpu().float()
|
||||||
|
out_masks = torch.cat(mask_list, dim=0)
|
||||||
|
return (out_images, out_masks, 1.0 - out_masks,)
|
||||||
|
|
||||||
class MaskOrImageToWeight:
|
class MaskOrImageToWeight:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user