Spaces:
Running
on
Zero
Running
on
Zero
| #---------------------------------------------------------------------------------------------------------------------# | |
| # Comfyroll Studio custom nodes by RockOfFire and Akatsuzi https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes | |
| # for ComfyUI https://github.com/comfyanonymous/ComfyUI | |
| #---------------------------------------------------------------------------------------------------------------------# | |
| 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: | |
| 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'): | |
| # Get RGB values for the text and bar colors | |
| 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: | |
| # Calculate the height factor | |
| 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!\"" | |
| # Create PIL images for the image and text bars | |
| back_image = tensor2pil(img) | |
| size = back_image.width, int(back_image.height * height_factor) | |
| result_image = Image.new("RGB", size) | |
| # Define font settings | |
| #font_file = "fonts\\" + str(font_name) | |
| 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) | |
| # Create the drawing context | |
| draw = ImageDraw.Draw(result_image) | |
| # Create two color bars at the top and bottom | |
| bar_width = back_image.width | |
| bar_height = back_image.height // 5 ### add parameter for this in adv node | |
| top_bar = Image.new("RGB", (bar_width, bar_height), bar_color) | |
| bottom_bar = Image.new("RGB", (bar_width, bar_height), bar_color) | |
| # Composite the result image onto the input image | |
| 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)) | |
| # Get the font size and draw the text | |
| 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) | |
| # Overlay text on image | |
| 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) | |
| #image_out = np.array(result_image).astype(np.float32) / 255.0 | |
| #image_out = torch.from_numpy(image_out).unsqueeze(0) | |
| # Convert the PIL image back to a torch tensor | |
| #return (pil2tensor(image_out), show_help, ) | |
| #return (image_out, show_help, ) | |
| # Convert to tensor | |
| 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) | |
| # Batch the images | |
| 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: | |
| 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",), | |
| #"image_opacity": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.1}), | |
| "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,), | |
| #"text_opacity": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.1}), | |
| #"drop_shadow_angle": ("INT", {"default": 0, "min": 0, "max": 500}), | |
| #"drop_shadow_offset": ("INT", {"default": 0, "min": 0, "max": 500}), | |
| #"drop_shadow_color": (COLORS,), | |
| #"drop_shadow_opacity": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.1}), | |
| #"wrap_text": (["true", "false"],), | |
| "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'): | |
| # Get RGB values for the text and bar colors | |
| 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: | |
| # Create PIL images for the image and text bars | |
| back_image = tensor2pil(img).convert("RGBA") | |
| size = back_image.width, back_image.height | |
| #result_image = Image.new("RGB", size) | |
| # Define font settings | |
| 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) | |
| # Create the drawing context | |
| draw = ImageDraw.Draw(back_image) | |
| area_width = back_image.width - (margin_size * 2) | |
| area_height = back_image.width - (margin_size * 2) | |
| # Get the font size and draw the text | |
| 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') | |
| # Convert to tensor | |
| 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) | |
| # Batch the images | |
| 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: | |
| 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 | |
| # Convert tensor images to PIL | |
| if images is not None: | |
| images = [tensor2pil(image) for image in images] | |
| len_images = len(images) | |
| # Get RGB values for the text and background colors | |
| 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) | |
| # Create page and apply bg color | |
| 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 | |
| # Calculate panel positions and add to bg image | |
| 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 | |
| # Row loop | |
| for i in range(rows): | |
| # Column Loop | |
| for j in range(columns): | |
| # Draw the panel | |
| 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): | |
| # Draw the panel | |
| 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): | |
| # Draw the panel | |
| 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 | |
| # Add a border to the page | |
| 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: | |
| 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" | |
| # Get RGB values for the text and background colors | |
| 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) | |
| # Get image width and height | |
| 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") | |
| # Set defaults | |
| 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 | |
| ### Create text panel for image 1 | |
| 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') | |
| # Apply the outline | |
| if outline_thickness > 0: | |
| combined_img1 = ImageOps.expand(combined_img1, outline_thickness, fill=bg_color) | |
| ### Create text panel for image 2 | |
| 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) | |
| # Add a border to the combined image | |
| if border_thickness > 0: | |
| result_img = ImageOps.expand(result_img, border_thickness, bg_color) | |
| return (pil2tensor(result_img), show_help, ) | |
| #--------------------------------------------------------------------------------------------------------------------- | |
| class CR_ThumbnailPreview: | |
| 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) | |
| # based on ETN_SendImageWebSocket | |
| 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: | |
| 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) | |
| # based on ETN_SendImageWebSocket | |
| 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,) } | |
| #---------------------------------------------------------------------------------------------------------------------# | |
| # MAPPINGS | |
| #---------------------------------------------------------------------------------------------------------------------# | |
| # For reference only, actual mappings are in __init__.py | |
| ''' | |
| 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, | |
| } | |
| ''' | |