feat: 🔥 add any to string & refactor

This commit is contained in:
melMass
2023-08-10 23:31:46 +02:00
parent 40560f8154
commit dbdb872b74
4 changed files with 157 additions and 112 deletions
+2 -109
View File
@@ -1,5 +1,4 @@
from ..utils import pil2tensor
from ..utils import here, comfy_dir
from ..utils import here
from ..log import log
import folder_paths
from pathlib import Path
@@ -97,110 +96,4 @@ class StylesLoader:
return (self.options[style_name][0], self.options[style_name][1])
class TextToImage:
"""Utils to convert text to image using a font
The tool looks for any .ttf file in the Comfy folder hierarchy.
"""
fonts = {}
def __init__(self):
# - This is executed when the graph is executed, we could conditionaly reload fonts there
pass
@classmethod
def CACHE_FONTS(cls):
font_extensions = ["*.ttf", "*.otf", "*.woff", "*.woff2", "*.eot"]
fonts = []
for extension in font_extensions:
fonts.extend(comfy_dir.glob(f"**/{extension}"))
if not fonts:
log.warn(
"> No fonts found in the comfy folder, place at least one font file somewhere in ComfyUI's hierarchy"
)
else:
log.debug(f"> Found {len(fonts)} fonts")
for font in fonts:
log.debug(f"Adding font {font}")
cls.fonts[font.stem] = font.as_posix()
@classmethod
def INPUT_TYPES(cls):
if not cls.fonts:
cls.CACHE_FONTS()
else:
log.debug(f"Using cached fonts (count: {len(cls.fonts)})")
return {
"required": {
"text": (
"STRING",
{"default": "Hello world!"},
),
"font": ((sorted(cls.fonts.keys())),),
"wrap": (
"INT",
{"default": 120, "min": 0, "max": 8096, "step": 1},
),
"font_size": (
"INT",
{"default": 12, "min": 1, "max": 2500, "step": 1},
),
"width": (
"INT",
{"default": 512, "min": 1, "max": 8096, "step": 1},
),
"height": (
"INT",
{"default": 512, "min": 1, "max": 8096, "step": 1},
),
# "position": (["INT"], {"default": 0, "min": 0, "max": 100, "step": 1}),
"color": (
"COLOR",
{"default": "black"},
),
"background": (
"COLOR",
{"default": "white"},
),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = "text_to_image"
CATEGORY = "mtb/generate"
def text_to_image(
self, text, font, wrap, font_size, width, height, color, background
):
from PIL import Image, ImageDraw, ImageFont
import textwrap
font = self.fonts[font]
font = ImageFont.truetype(font, font_size)
if wrap == 0:
wrap = width / font_size
lines = textwrap.wrap(text, width=wrap)
log.debug(f"Lines: {lines}")
line_height = font.getsize("hg")[1]
img_height = height # line_height * len(lines)
img_width = width # max(font.getsize(line)[0] for line in lines)
img = Image.new("RGBA", (img_width, img_height), background)
draw = ImageDraw.Draw(img)
y_text = 0
for line in lines:
width, height = font.getsize(line)
draw.text((0, y_text), line, color, font=font)
y_text += height
# img.save(os.path.join(folder_paths.base_path, f'{str(uuid.uuid4())}.png'))
return (pil2tensor(img),)
__nodes__ = [SmartStep, TextToImage, StylesLoader]
__nodes__ = [SmartStep, StylesLoader]
+121 -1
View File
@@ -1,5 +1,7 @@
import qrcode
from ..utils import pil2tensor
from ..utils import comfy_dir
from typing import cast
from PIL import Image
from ..log import log
@@ -130,6 +132,9 @@ class QrCode:
CATEGORY = "mtb/generate"
def do_qr(self, url, width, height, error_correct, box_size, border, invert):
log.warning(
"This node will soon be deprecated, there are much better alternatives like https://github.com/coreyryanhanson/comfy-qr"
)
if error_correct == "L" or error_correct not in ["M", "Q", "H"]:
error_correct = qrcode.constants.ERROR_CORRECT_L
elif error_correct == "M":
@@ -159,8 +164,123 @@ class QrCode:
return (pil2tensor(code),)
def bbox_dim(bbox):
left, upper, right, lower = bbox
width = right - left
height = lower - upper
return width, height
class TextToImage:
"""Utils to convert text to image using a font
The tool looks for any .ttf file in the Comfy folder hierarchy.
"""
fonts = {}
def __init__(self):
# - This is executed when the graph is executed, we could conditionaly reload fonts there
pass
@classmethod
def CACHE_FONTS(cls):
font_extensions = ["*.ttf", "*.otf", "*.woff", "*.woff2", "*.eot"]
fonts = []
for extension in font_extensions:
fonts.extend(comfy_dir.glob(f"**/{extension}"))
if not fonts:
log.warn(
"> No fonts found in the comfy folder, place at least one font file somewhere in ComfyUI's hierarchy"
)
else:
log.debug(f"> Found {len(fonts)} fonts")
for font in fonts:
log.debug(f"Adding font {font}")
cls.fonts[font.stem] = font.as_posix()
@classmethod
def INPUT_TYPES(cls):
if not cls.fonts:
cls.CACHE_FONTS()
else:
log.debug(f"Using cached fonts (count: {len(cls.fonts)})")
return {
"required": {
"text": (
"STRING",
{"default": "Hello world!"},
),
"font": ((sorted(cls.fonts.keys())),),
"wrap": (
"INT",
{"default": 120, "min": 0, "max": 8096, "step": 1},
),
"font_size": (
"INT",
{"default": 12, "min": 1, "max": 2500, "step": 1},
),
"width": (
"INT",
{"default": 512, "min": 1, "max": 8096, "step": 1},
),
"height": (
"INT",
{"default": 512, "min": 1, "max": 8096, "step": 1},
),
# "position": (["INT"], {"default": 0, "min": 0, "max": 100, "step": 1}),
"color": (
"COLOR",
{"default": "black"},
),
"background": (
"COLOR",
{"default": "white"},
),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = "text_to_image"
CATEGORY = "mtb/generate"
def text_to_image(
self, text, font, wrap, font_size, width, height, color, background
):
from PIL import Image, ImageDraw, ImageFont
import textwrap
font = self.fonts[font]
font = cast(ImageFont.FreeTypeFont, ImageFont.truetype(font, font_size))
if wrap == 0:
wrap = width / font_size
lines = textwrap.wrap(text, width=wrap)
log.debug(f"Lines: {lines}")
line_height = bbox_dim(font.getbbox("hg"))[1]
img_height = height # line_height * len(lines)
img_width = width # max(font.getsize(line)[0] for line in lines)
img = Image.new("RGBA", (img_width, img_height), background)
draw = ImageDraw.Draw(img)
y_text = 0
# - bbox is [left, upper, right, lower]
for line in lines:
width, height = bbox_dim(font.getbbox(line))
draw.text((0, y_text), line, color, font=font)
y_text += height
# img.save(os.path.join(folder_paths.base_path, f'{str(uuid.uuid4())}.png'))
return (pil2tensor(img),)
__nodes__ = [
QrCode,
UnsplashImage
UnsplashImage,
TextToImage
# MtbExamples,
]
+33 -1
View File
@@ -7,6 +7,7 @@ import json
from comfy.cli_args import args
from ..utils import pil2tensor
import io
import numpy as np
def get_image(filename, subfolder, folder_type):
@@ -107,6 +108,37 @@ class GetBatchFromHistory:
return (output,)
class AnyToString:
"""Tries to take any input and convert it to a string"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {"input": ("*")},
}
RETURN_TYPES = ("STRING",)
FUNCTION = "do_str"
CATEGORY = "mtb/converters"
def do_str(self, input):
if isinstance(input, str):
return (input,)
elif isinstance(input, torch.Tensor):
return (f"Tensor of shape {input.shape} and dtype {input.dtype}",)
elif isinstance(input, Image.Image):
return (f"PIL Image of size {input.size} and mode {input.mode}",)
elif isinstance(input, np.ndarray):
return (f"Numpy array of shape {input.shape} and dtype {input.dtype}",)
elif isinstance(input, dict):
return (f"Dictionary of {len(input)} items, with keys {input.keys()}",)
else:
log.debug(f"Falling back to string conversion of {input}")
return (str(input),)
class StringReplace:
"""Basic string replacement"""
@@ -178,4 +210,4 @@ class FitNumber:
return (res,)
__nodes__ = [StringReplace, FitNumber, GetBatchFromHistory]
__nodes__ = [StringReplace, FitNumber, GetBatchFromHistory, AnyToString]
+1 -1
View File
@@ -60,7 +60,7 @@ export function offsetDOMWidget(
*/
export function getWidgetType(config) {
// Special handling for COMBO so we restrict links based on the entries
let type = config[0]
let type = config?.[0]
let linkType = type
if (type instanceof Array) {
type = 'COMBO'