|
|
|
|
|
|
|
|
|
|
|
import numpy as np |
|
import torch |
|
import os |
|
from PIL import Image, ImageDraw, ImageOps, ImageFont |
|
from server import PromptServer, BinaryEventTypes |
|
|
|
from ..categories import icons |
|
from ..config import color_mapping, COLORS |
|
from .functions_graphics import * |
|
from .functions_upscale import apply_resize_image |
|
|
|
font_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "fonts") |
|
file_list = [f for f in os.listdir(font_dir) if os.path.isfile(os.path.join(font_dir, f)) and f.lower().endswith(".ttf")] |
|
|
|
|
|
|
|
ALIGN_OPTIONS = ["top", "center", "bottom"] |
|
ROTATE_OPTIONS = ["text center", "image center"] |
|
JUSTIFY_OPTIONS = ["left", "center", "right"] |
|
PERSPECTIVE_OPTIONS = ["top", "bottom", "left", "right"] |
|
|
|
|
|
class CR_SimpleMemeTemplate: |
|
|
|
@classmethod |
|
def INPUT_TYPES(s): |
|
|
|
font_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "fonts") |
|
file_list = [f for f in os.listdir(font_dir) if os.path.isfile(os.path.join(font_dir, f)) and f.lower().endswith(".ttf")] |
|
bar_opts = ["no bars", "top", "bottom", "top and bottom"] |
|
simple_meme_presets = ["custom", |
|
"One Does Not Simply ... MEME IN COMFY", |
|
"This is fine.", |
|
"Good Morning ... No Such Thing!"] |
|
|
|
return {"required": { |
|
"image": ("IMAGE",), |
|
"preset": (simple_meme_presets,), |
|
"text_top": ("STRING", {"multiline": True, "default": "text_top"}), |
|
"text_bottom": ("STRING", {"multiline": True, "default": "text_bottom"}), |
|
"font_name": (file_list,), |
|
"max_font_size": ("INT", {"default": 150, "min": 20, "max": 2048}), |
|
"font_color": (COLORS,), |
|
"font_outline": (["none", "thin", "thick", "extra thick"],), |
|
"bar_color": (COLORS,), |
|
"bar_options": (bar_opts,), |
|
}, |
|
"optional": { |
|
"font_color_hex": ("STRING", {"multiline": False, "default": "#000000"}), |
|
"bar_color_hex": ("STRING", {"multiline": False, "default": "#000000"}) |
|
} |
|
} |
|
|
|
RETURN_TYPES = ("IMAGE", "STRING", ) |
|
RETURN_NAMES = ("image", "show_help", ) |
|
FUNCTION = "make_meme" |
|
CATEGORY = icons.get("Comfyroll/Graphics/Template") |
|
|
|
def make_meme(self, image, preset, |
|
text_top, text_bottom, |
|
font_name, max_font_size, font_color, font_outline, |
|
bar_color, bar_options, |
|
font_color_hex='#000000', bar_color_hex='#000000'): |
|
|
|
|
|
text_color = get_color_values(font_color, font_color_hex, color_mapping) |
|
bar_color = get_color_values(bar_color, bar_color_hex, color_mapping) |
|
|
|
total_images = [] |
|
|
|
for img in image: |
|
|
|
|
|
if bar_options == "top": |
|
height_factor = 1.2 |
|
elif bar_options == "bottom": |
|
height_factor = 1.2 |
|
elif bar_options == "top and bottom": |
|
height_factor = 1.4 |
|
else: |
|
height_factor = 1.0 |
|
|
|
if preset == "One Does Not Simply ... MEME IN COMFY": |
|
text_top = "One Does Not Simply" |
|
text_bottom = "MEME IN COMFY" |
|
if preset == "This is fine.": |
|
text_top = "This is fine." |
|
text_bottom = "" |
|
if preset == "Good Morning ... No Such Thing!": |
|
text_top = "Good Morning" |
|
text_bottom = "\"No Such Thing!\"" |
|
|
|
|
|
back_image = tensor2pil(img) |
|
size = back_image.width, int(back_image.height * height_factor) |
|
result_image = Image.new("RGB", size) |
|
|
|
|
|
|
|
font_file = os.path.join("fonts", font_name) |
|
resolved_font_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), font_file) |
|
|
|
|
|
draw = ImageDraw.Draw(result_image) |
|
|
|
|
|
bar_width = back_image.width |
|
bar_height = back_image.height // 5 |
|
top_bar = Image.new("RGB", (bar_width, bar_height), bar_color) |
|
bottom_bar = Image.new("RGB", (bar_width, bar_height), bar_color) |
|
|
|
|
|
if bar_options == "top" or bar_options == "top and bottom": |
|
image_out = result_image.paste(back_image, (0, bar_height)) |
|
else: |
|
image_out = result_image.paste(back_image, (0, 0)) |
|
|
|
|
|
if bar_options == "top" or bar_options == "top and bottom": |
|
result_image.paste(top_bar, (0, 0)) |
|
font_top = get_font_size(draw, text_top, bar_width, bar_height, resolved_font_path, max_font_size) |
|
draw_text_on_image(draw, 0, bar_width, bar_height, text_top, font_top, text_color, font_outline) |
|
|
|
if bar_options == "bottom" or bar_options == "top and bottom": |
|
result_image.paste(bottom_bar, (0, (result_image.height - bar_height))) |
|
font_bottom = get_font_size(draw, text_bottom, bar_width, bar_height, resolved_font_path, max_font_size) |
|
if bar_options == "bottom": |
|
y_position = back_image.height |
|
else: |
|
y_position = bar_height + back_image.height |
|
draw_text_on_image(draw, y_position, bar_width, bar_height, text_bottom, font_bottom, text_color, font_outline) |
|
|
|
|
|
if bar_options == "bottom" and text_top > "": |
|
font_top = get_font_size(draw, text_top, bar_width, bar_height, resolved_font_path, max_font_size) |
|
draw_text_on_image(draw, 0, bar_width, bar_height, text_top, font_top, text_color, font_outline) |
|
|
|
if (bar_options == "top" or bar_options == "none") and text_bottom > "": |
|
font_bottom = get_font_size(draw, text_bottom, bar_width, bar_height, resolved_font_path, max_font_size) |
|
y_position = back_image.height |
|
draw_text_on_image(draw, y_position, bar_width, bar_height, text_bottom, font_bottom, text_color, font_outline) |
|
|
|
if bar_options == "no bars" and text_bottom > "": |
|
font_bottom = get_font_size(draw, text_bottom, bar_width, bar_height, resolved_font_path, max_font_size) |
|
y_position = back_image.height - bar_height |
|
draw_text_on_image(draw, y_position, bar_width, bar_height, text_bottom, font_bottom, text_color, font_outline) |
|
|
|
if bar_options == "no bars" and text_top > "": |
|
font_top = get_font_size(draw, text_top, bar_width, bar_height, resolved_font_path, max_font_size) |
|
draw_text_on_image(draw, 0, bar_width, bar_height, text_top, font_top, text_color, font_outline) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
out_image = np.array(result_image.convert("RGB")).astype(np.float32) / 255.0 |
|
out_image = torch.from_numpy(out_image).unsqueeze(0) |
|
total_images.append(out_image) |
|
|
|
|
|
images_out = torch.cat(total_images, 0) |
|
|
|
show_help = "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes/wiki/Template-Nodes#cr-simple-meme-template" |
|
|
|
return (images_out, show_help, ) |
|
|
|
|
|
class CR_SimpleBanner: |
|
|
|
@classmethod |
|
def INPUT_TYPES(s): |
|
|
|
font_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "fonts") |
|
file_list = [f for f in os.listdir(font_dir) if os.path.isfile(os.path.join(font_dir, f)) and f.lower().endswith(".ttf")] |
|
|
|
return {"required": { |
|
"image": ("IMAGE",), |
|
|
|
"banner_text": ("STRING", {"multiline": True, "default": "text"}), |
|
"font_name": (file_list,), |
|
"max_font_size": ("INT", {"default": 150, "min": 20, "max": 2048}), |
|
"font_color": (COLORS,), |
|
"outline_thickness": ("INT", {"default": 0, "min": 0, "max": 500}), |
|
"outline_color": (COLORS,), |
|
|
|
|
|
|
|
|
|
|
|
|
|
"margin_size": ("INT", {"default": 0, "min": 0, "max": 500}), |
|
}, |
|
"optional": { |
|
"font_color_hex": ("STRING", {"multiline": False, "default": "#000000"}), |
|
"outline_color_hex": ("STRING", {"multiline": False, "default": "#000000"}), |
|
} |
|
} |
|
|
|
RETURN_TYPES = ("IMAGE", "STRING", ) |
|
RETURN_NAMES = ("image", "show_help", ) |
|
FUNCTION = "make_banner" |
|
CATEGORY = icons.get("Comfyroll/Graphics/Template") |
|
|
|
def make_banner(self, image, banner_text, |
|
font_name, max_font_size, font_color, |
|
outline_thickness, outline_color, margin_size, |
|
font_color_hex='#000000', outline_color_hex='#000000'): |
|
|
|
|
|
text_color = get_color_values(font_color, font_color_hex, color_mapping) |
|
outline_color = get_color_values(outline_color, outline_color_hex, color_mapping) |
|
|
|
total_images = [] |
|
|
|
for img in image: |
|
|
|
|
|
back_image = tensor2pil(img).convert("RGBA") |
|
size = back_image.width, back_image.height |
|
|
|
|
|
|
|
font_file = os.path.join("fonts", font_name) |
|
resolved_font_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), font_file) |
|
|
|
|
|
draw = ImageDraw.Draw(back_image) |
|
|
|
area_width = back_image.width - (margin_size * 2) |
|
area_height = back_image.width - (margin_size * 2) |
|
|
|
|
|
font = get_font_size(draw, banner_text, area_width, area_height, resolved_font_path, max_font_size) |
|
|
|
x = back_image.width // 2 |
|
y = back_image.height // 2 |
|
|
|
if outline_thickness > 0: |
|
draw.text((x, y), banner_text, fill=text_color, font=font, anchor='mm', stroke_width=outline_thickness, stroke_fill=outline_color) |
|
else: |
|
draw.text((x, y), banner_text, fill=text_color, font=font, anchor='mm') |
|
|
|
|
|
out_image = np.array(back_image.convert("RGB")).astype(np.float32) / 255.0 |
|
out_image = torch.from_numpy(out_image).unsqueeze(0) |
|
total_images.append(out_image) |
|
|
|
|
|
images_out = torch.cat(total_images, 0) |
|
|
|
show_help = "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes/wiki/Template-Nodes#cr-simple-banner" |
|
|
|
return (images_out, show_help, ) |
|
|
|
|
|
class CR_ComicPanelTemplates: |
|
|
|
@classmethod |
|
def INPUT_TYPES(s): |
|
|
|
directions = ["left to right", "right to left"] |
|
|
|
templates = ["custom", |
|
"G22", "G33", |
|
"H2", "H3", |
|
"H12", "H13", |
|
"H21", "H23", |
|
"H31", "H32", |
|
"V2", "V3", |
|
"V12", "V13", |
|
"V21", "V23", |
|
"V31", "V32"] |
|
|
|
return {"required": { |
|
"page_width": ("INT", {"default": 512, "min": 8, "max": 4096}), |
|
"page_height": ("INT", {"default": 512, "min": 8, "max": 4096}), |
|
"template": (templates,), |
|
"reading_direction": (directions,), |
|
"border_thickness": ("INT", {"default": 5, "min": 0, "max": 1024}), |
|
"outline_thickness": ("INT", {"default": 2, "min": 0, "max": 1024}), |
|
"outline_color": (COLORS,), |
|
"panel_color": (COLORS,), |
|
"background_color": (COLORS,), |
|
}, |
|
"optional": { |
|
"images": ("IMAGE",), |
|
"custom_panel_layout": ("STRING", {"multiline": False, "default": "H123"}), |
|
"outline_color_hex": ("STRING", {"multiline": False, "default": "#000000"}), |
|
"panel_color_hex": ("STRING", {"multiline": False, "default": "#000000"}), |
|
"bg_color_hex": ("STRING", {"multiline": False, "default": "#000000"}), |
|
} |
|
} |
|
|
|
RETURN_TYPES = ("IMAGE", "STRING", ) |
|
RETURN_NAMES = ("image", "show_help", ) |
|
FUNCTION = "layout" |
|
CATEGORY = icons.get("Comfyroll/Graphics/Template") |
|
|
|
def layout(self, page_width, page_height, template, reading_direction, |
|
border_thickness, outline_thickness, |
|
outline_color, panel_color, background_color, |
|
images=None, custom_panel_layout='G44', |
|
outline_color_hex='#000000', panel_color_hex='#000000', bg_color_hex='#000000'): |
|
|
|
panels = [] |
|
k = 0 |
|
len_images = 0 |
|
|
|
|
|
if images is not None: |
|
images = [tensor2pil(image) for image in images] |
|
len_images = len(images) |
|
|
|
|
|
outline_color = get_color_values(outline_color, outline_color_hex, color_mapping) |
|
panel_color = get_color_values(panel_color, panel_color_hex, color_mapping) |
|
bg_color = get_color_values(background_color, bg_color_hex, color_mapping) |
|
|
|
|
|
size = (page_width - (2 * border_thickness), page_height - (2 * border_thickness)) |
|
page = Image.new('RGB', size, bg_color) |
|
draw = ImageDraw.Draw(page) |
|
|
|
if template == "custom": |
|
template = custom_panel_layout |
|
|
|
|
|
first_char = template[0] |
|
if first_char == "G": |
|
rows = int(template[1]) |
|
columns = int(template[2]) |
|
panel_width = (page.width - (2 * columns * (border_thickness + outline_thickness))) // columns |
|
panel_height = (page.height - (2 * rows * (border_thickness + outline_thickness))) // rows |
|
|
|
for i in range(rows): |
|
|
|
for j in range(columns): |
|
|
|
create_and_paste_panel(page, border_thickness, outline_thickness, |
|
panel_width, panel_height, page.width, |
|
panel_color, bg_color, outline_color, |
|
images, i, j, k, len_images, reading_direction) |
|
k += 1 |
|
|
|
elif first_char == "H": |
|
rows = len(template) - 1 |
|
panel_height = (page.height - (2 * rows * (border_thickness + outline_thickness))) // rows |
|
for i in range(rows): |
|
columns = int(template[i+1]) |
|
panel_width = (page.width - (2 * columns * (border_thickness + outline_thickness))) // columns |
|
for j in range(columns): |
|
|
|
create_and_paste_panel(page, border_thickness, outline_thickness, |
|
panel_width, panel_height, page.width, |
|
panel_color, bg_color, outline_color, |
|
images, i, j, k, len_images, reading_direction) |
|
k += 1 |
|
|
|
elif first_char == "V": |
|
columns = len(template) - 1 |
|
panel_width = (page.width - (2 * columns * (border_thickness + outline_thickness))) // columns |
|
for j in range(columns): |
|
rows = int(template[j+1]) |
|
panel_height = (page.height - (2 * rows * (border_thickness + outline_thickness))) // rows |
|
for i in range(rows): |
|
|
|
create_and_paste_panel(page, border_thickness, outline_thickness, |
|
panel_width, panel_height, page.width, |
|
panel_color, bg_color, outline_color, |
|
images, i, j, k, len_images, reading_direction) |
|
k += 1 |
|
|
|
|
|
if border_thickness > 0: |
|
page = ImageOps.expand(page, border_thickness, bg_color) |
|
|
|
show_help = "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes/wiki/Template-Nodes#cr-comic-panel-templates" |
|
|
|
return (pil2tensor(page), show_help, ) |
|
|
|
|
|
class CR_SimpleImageCompare: |
|
|
|
@classmethod |
|
def INPUT_TYPES(s): |
|
|
|
font_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "fonts") |
|
file_list = [f for f in os.listdir(font_dir) if os.path.isfile(os.path.join(font_dir, f)) and f.lower().endswith(".ttf")] |
|
|
|
return {"required": { |
|
"text1": ("STRING", {"multiline": True, "default": "text"}), |
|
"text2": ("STRING", {"multiline": True, "default": "text"}), |
|
"footer_height": ("INT", {"default": 100, "min": 0, "max": 1024}), |
|
"font_name": (file_list,), |
|
"font_size": ("INT", {"default": 50, "min": 0, "max": 1024}), |
|
"mode": (["normal", "dark"],), |
|
"border_thickness": ("INT", {"default": 20, "min": 0, "max": 1024}), |
|
}, |
|
"optional": { |
|
"image1": ("IMAGE",), |
|
"image2": ("IMAGE",), |
|
} |
|
|
|
} |
|
|
|
RETURN_TYPES = ("IMAGE", "STRING", ) |
|
RETURN_NAMES = ("image", "show_help", ) |
|
FUNCTION = "layout" |
|
CATEGORY = icons.get("Comfyroll/Graphics/Template") |
|
|
|
def layout(self, text1, text2, |
|
footer_height, font_name, font_size, mode, |
|
border_thickness, image1=None, image2=None): |
|
|
|
show_help = "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes/wiki/Layout-Nodes#cr-simple-image-compare" |
|
|
|
|
|
if mode == "normal": |
|
font_color = "black" |
|
bg_color = "white" |
|
else: |
|
font_color = "white" |
|
bg_color = "black" |
|
|
|
if image1 is not None and image2 is not None: |
|
|
|
img1 = tensor2pil(image1) |
|
img2 = tensor2pil(image2) |
|
|
|
|
|
image_width, image_height = img1.width, img1.height |
|
|
|
if img2.width != img1.width or img2.height != img1.height: |
|
img2 = apply_resize_image(img2, image_width, image_height, 8, "rescale", "false", 1, 256, "lanczos") |
|
|
|
|
|
margins = 50 |
|
line_spacing = 0 |
|
position_x = 0 |
|
position_y = 0 |
|
align = "center" |
|
rotation_angle = 0 |
|
rotation_options = "image center" |
|
font_outline_thickness = 0 |
|
font_outline_color = "black" |
|
align = "center" |
|
footer_align = "center" |
|
outline_thickness = border_thickness//2 |
|
border_thickness = border_thickness//2 |
|
|
|
|
|
if footer_height >0: |
|
text_panel1 = text_panel(image_width, footer_height, text1, |
|
font_name, font_size, font_color, |
|
font_outline_thickness, font_outline_color, |
|
bg_color, |
|
margins, line_spacing, |
|
position_x, position_y, |
|
align, footer_align, |
|
rotation_angle, rotation_options) |
|
|
|
combined_img1 = combine_images([img1, text_panel1], 'vertical') |
|
|
|
|
|
if outline_thickness > 0: |
|
combined_img1 = ImageOps.expand(combined_img1, outline_thickness, fill=bg_color) |
|
|
|
|
|
if footer_height >0: |
|
text_panel2 = text_panel(image_width, footer_height, text2, |
|
font_name, font_size, font_color, |
|
font_outline_thickness, font_outline_color, |
|
bg_color, |
|
margins, line_spacing, |
|
position_x, position_y, |
|
align, footer_align, |
|
rotation_angle, rotation_options) |
|
|
|
combined_img2 = combine_images([img2, text_panel2], 'vertical') |
|
|
|
if outline_thickness > 0: |
|
combined_img2 = ImageOps.expand(combined_img2, outline_thickness, fill=bg_color) |
|
|
|
result_img = combine_images([combined_img1, combined_img2], 'horizontal') |
|
else: |
|
result_img = Image.new('RGB', (512,512), bg_color) |
|
|
|
|
|
if border_thickness > 0: |
|
result_img = ImageOps.expand(result_img, border_thickness, bg_color) |
|
|
|
return (pil2tensor(result_img), show_help, ) |
|
|
|
|
|
class CR_ThumbnailPreview: |
|
|
|
@classmethod |
|
def INPUT_TYPES(s): |
|
|
|
return {"required": |
|
{"image": ("IMAGE",), |
|
"rescale_factor": ("FLOAT", {"default": 0.25, "min": 0.10, "max": 1.00, "step": 0.01}), |
|
"max_columns": ("INT", {"default": 5, "min": 0, "max": 256}), |
|
} |
|
} |
|
|
|
RETURN_TYPES = ("STRING", ) |
|
RETURN_NAMES = ("show_help", ) |
|
OUTPUT_NODE = True |
|
FUNCTION = "thumbnail" |
|
CATEGORY = icons.get("Comfyroll/Graphics/Template") |
|
|
|
def thumbnail(self, image, rescale_factor, max_columns): |
|
|
|
show_help = "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes/wiki/Template-Nodes#cr-thumbnail-preview" |
|
|
|
result_images = [] |
|
outline_thickness = 1 |
|
|
|
for img in image: |
|
pil_img = tensor2pil(img) |
|
original_width, original_height = pil_img.size |
|
rescaled_img = apply_resize_image(tensor2pil(img), original_width, original_height, 8, "rescale", "false", rescale_factor, 256, "lanczos") |
|
outlined_img = ImageOps.expand(rescaled_img, outline_thickness, fill="black") |
|
result_images.append(outlined_img) |
|
|
|
combined_image = make_grid_panel(result_images, max_columns) |
|
images_out = pil2tensor(combined_image) |
|
|
|
|
|
results = [] |
|
|
|
for tensor in images_out: |
|
array = 255.0 * tensor.cpu().numpy() |
|
image = Image.fromarray(np.clip(array, 0, 255).astype(np.uint8)) |
|
|
|
server = PromptServer.instance |
|
server.send_sync( |
|
BinaryEventTypes.UNENCODED_PREVIEW_IMAGE, |
|
["PNG", image, None], |
|
server.client_id, |
|
) |
|
results.append({"source": "websocket", "content-type": "image/png", "type": "output"}) |
|
|
|
return {"ui": {"images": results}, "result": (show_help,) } |
|
|
|
|
|
class CR_SeamlessChecker: |
|
|
|
@classmethod |
|
def INPUT_TYPES(s): |
|
|
|
return {"required": |
|
{"image": ("IMAGE",), |
|
"rescale_factor": ("FLOAT", {"default": 0.25, "min": 0.10, "max": 1.00, "step": 0.01}), |
|
"grid_options": (["2x2", "3x3", "4x4", "5x5", "6x6"],), |
|
} |
|
} |
|
|
|
RETURN_TYPES = ("STRING", ) |
|
RETURN_NAMES = ("show_help", ) |
|
OUTPUT_NODE = True |
|
FUNCTION = "thumbnail" |
|
CATEGORY = icons.get("Comfyroll/Graphics/Template") |
|
|
|
def thumbnail(self, image, rescale_factor, grid_options): |
|
|
|
show_help = "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes/wiki/Other-Nodes#cr-seamless-checker" |
|
|
|
outline_thickness = 0 |
|
|
|
pil_img = tensor2pil(image) |
|
original_width, original_height = pil_img.size |
|
rescaled_img = apply_resize_image(tensor2pil(image), original_width, original_height, 8, "rescale", "false", rescale_factor, 256, "lanczos") |
|
outlined_img = ImageOps.expand(rescaled_img, outline_thickness, fill="black") |
|
|
|
max_columns = int(grid_options[0]) |
|
repeat_images = [outlined_img] * max_columns ** 2 |
|
|
|
combined_image = make_grid_panel(repeat_images, max_columns) |
|
images_out = pil2tensor(combined_image) |
|
|
|
|
|
results = [] |
|
|
|
for tensor in images_out: |
|
array = 255.0 * tensor.cpu().numpy() |
|
image = Image.fromarray(np.clip(array, 0, 255).astype(np.uint8)) |
|
|
|
server = PromptServer.instance |
|
server.send_sync( |
|
BinaryEventTypes.UNENCODED_PREVIEW_IMAGE, |
|
["PNG", image, None], |
|
server.client_id, |
|
) |
|
results.append({"source": "websocket", "content-type": "image/png", "type": "output"}) |
|
|
|
return {"ui": {"images": results}, "result": (show_help,) } |
|
|
|
|
|
|
|
|
|
|
|
''' |
|
NODE_CLASS_MAPPINGS = { |
|
"CR Simple Meme Template": CR_SimpleMemeTemplate, |
|
"CR Simple Banner": CR_SimpleBanner, |
|
"CR Comic Panel Templates": CR_ComicPanelTemplates, |
|
"CR Simple Image Compare": CR_SimpleImageCompare, |
|
"CR Thumbnail Preview": CR_ThumbnailPreview, |
|
"CR Seamless Checker": CR_SeamlessChecker, |
|
} |
|
''' |
|
|
|
|