Files
jaidaken f09734b0ee
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Includes 30 custom nodes committed directly, 7 Civitai-exclusive
loras stored via Git LFS, and a setup script that installs all
dependencies and downloads HuggingFace-hosted models on vast.ai.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 00:56:42 +00:00

3544 lines
143 KiB
Python

"""
@author: JPS
@title: JPS Custom Nodes for ComfyUI
@nickname: JPS Custom Nodes
@description: Various nodes to handle SDXL Resolutions, SDXL Basic Settings, IP Adapter Settings, Revision Settings, SDXL Prompt Styler, Crop Image to Square, Crop Image to Target Size, Get Date-Time String, Resolution Multiply, Largest Integer, 5-to-1 Switches for Integer, Images, Latents, Conditioning, Model, VAE, ControlNet
"""
#------------------------------------------------------------------------#
# JPS Custom Nodes https://github.com/JPS-GER/ComfyUI_JPS-Nodes #
# for ComfyUI https://github.com/comfyanonymous/ComfyUI #
#------------------------------------------------------------------------#
import torch
import json
import os
import comfy.sd
import folder_paths
from datetime import datetime
from PIL import Image, ImageOps, ImageSequence
import numpy as np
from PIL.PngImagePlugin import PngInfo
from comfy.cli_args import args
import torch.nn.functional as F
def min_(tensor_list):
# return the element-wise min of the tensor list.
x = torch.stack(tensor_list)
mn = x.min(axis=0)[0]
return torch.clamp(mn, min=0)
def max_(tensor_list):
# return the element-wise max of the tensor list.
x = torch.stack(tensor_list)
mx = x.max(axis=0)[0]
return torch.clamp(mx, max=1)
# From https://github.com/Jamy-L/Pytorch-Contrast-Adaptive-Sharpening/
def contrast_adaptive_sharpening(image, amount):
img = F.pad(image, pad=(1, 1, 1, 1)).cpu()
a = img[..., :-2, :-2]
b = img[..., :-2, 1:-1]
c = img[..., :-2, 2:]
d = img[..., 1:-1, :-2]
e = img[..., 1:-1, 1:-1]
f = img[..., 1:-1, 2:]
g = img[..., 2:, :-2]
h = img[..., 2:, 1:-1]
i = img[..., 2:, 2:]
# Computing contrast
cross = (b, d, e, f, h)
mn = min_(cross)
mx = max_(cross)
diag = (a, c, g, i)
mn2 = min_(diag)
mx2 = max_(diag)
mx = mx + mx2
mn = mn + mn2
# Computing local weight
inv_mx = torch.reciprocal(mx)
amp = inv_mx * torch.minimum(mn, (2 - mx))
# scaling
amp = torch.sqrt(amp)
w = - amp * (amount * (1/5 - 1/8) + 1/8)
div = torch.reciprocal(1 + 4*w)
output = ((b + d + f + h)*w + e) * div
output = output.clamp(0, 1)
output = torch.nan_to_num(output)
return (output)
def read_json_file(file_path):
"""
Reads a JSON file's content and returns it.
Ensures content matches the expected format.
"""
if not os.access(file_path, os.R_OK):
print(f"Warning: No read permissions for file {file_path}")
return None
try:
with open(file_path, 'r', encoding='utf-8') as file:
content = json.load(file)
# Check if the content matches the expected format.
if not all(['name' in item and 'prompt' in item and 'negative_prompt' in item for item in content]):
print(f"Warning: Invalid content in file {file_path}")
return None
return content
except Exception as e:
print(f"An error occurred while reading {file_path}: {str(e)}")
return None
def read_sdxl_styles(json_data):
"""
Returns style names from the provided JSON data.
"""
if not isinstance(json_data, list):
print("Error: input data must be a list")
return []
return [item['name'] for item in json_data if isinstance(item, dict) and 'name' in item]
def get_all_json_files(directory):
"""
Returns all JSON files from the specified directory.
"""
return [os.path.join(directory, file) for file in os.listdir(directory) if file.endswith('.json') and os.path.isfile(os.path.join(directory, file))]
def load_styles_from_directory(directory):
"""
Loads styles from all JSON files in the directory.
Renames duplicate style names by appending a suffix.
"""
json_files = get_all_json_files(directory)
combined_data = []
seen = set()
for json_file in json_files:
json_data = read_json_file(json_file)
if json_data:
for item in json_data:
original_style = item['name']
style = original_style
suffix = 1
while style in seen:
style = f"{original_style}_{suffix}"
suffix += 1
item['name'] = style
seen.add(style)
combined_data.append(item)
unique_style_names = [item['name'] for item in combined_data if isinstance(item, dict) and 'name' in item]
return combined_data, unique_style_names
def validate_json_data(json_data):
"""
Validates the structure of the JSON data.
"""
if not isinstance(json_data, list):
return False
for template in json_data:
if 'name' not in template or 'prompt' not in template:
return False
return True
def find_template_by_name(json_data, template_name):
"""
Returns a template from the JSON data by name or None if not found.
"""
for template in json_data:
if template['name'] == template_name:
return template
return None
def split_template(template: str) -> tuple:
"""
Splits a template into two parts based on a specific pattern.
"""
if "{prompt} ." in template:
template_prompt_g, template_prompt_l = template.split("{prompt} .", 1)
template_prompt_g = template_prompt_g.strip() + " {prompt}"
template_prompt_l = template_prompt_l.strip()
else:
template_prompt_g = template
template_prompt_l = ""
return template_prompt_g, template_prompt_l
def replace_prompts_in_template(template, positive_prompt_g, positive_prompt_l, negative_prompt):
"""
Replace the placeholders in a given template with the provided prompts and split them accordingly.
Args:
- template (dict): The template containing prompt placeholders.
- positive_prompt_g (str): The main positive prompt to replace '{prompt}' in the template.
- positive_prompt_l (str): The auxiliary positive prompt to be combined in a specific manner.
- negative_prompt (str): The negative prompt to be combined with any existing negative prompt in the template.
Returns:
- tuple: A tuple containing the replaced main positive, auxiliary positive, combined positive and negative prompts.
"""
template_prompt_g, template_prompt_l_template = split_template(template['prompt'])
text_g_positive = template_prompt_g.replace("{prompt}", positive_prompt_g)
text_l_positive = f"{template_prompt_l_template}, {positive_prompt_l}" if template_prompt_l_template and positive_prompt_l else template_prompt_l_template or positive_prompt_l
json_negative_prompt = template.get('negative_prompt', "")
text_negative = f"{json_negative_prompt}, {negative_prompt}" if json_negative_prompt and negative_prompt else json_negative_prompt or negative_prompt
return text_g_positive, text_l_positive, text_negative
def read_sdxl_templates_replace_and_combine(json_data, template_name, positive_prompt_g, positive_prompt_l, negative_prompt):
"""
Find a specific template by its name, then replace and combine its placeholders with the provided prompts in an advanced manner.
Args:
- json_data (list): The list of templates.
- template_name (str): The name of the desired template.
- positive_prompt_g (str): The main positive prompt.
- positive_prompt_l (str): The auxiliary positive prompt.
- negative_prompt (str): The negative prompt to be combined.
Returns:
- tuple: A tuple containing the replaced and combined main positive, auxiliary positive, combined positive and negative prompts.
"""
if not validate_json_data(json_data):
return positive_prompt_g, positive_prompt_l, negative_prompt
template = find_template_by_name(json_data, template_name)
if template:
return replace_prompts_in_template(template, positive_prompt_g, positive_prompt_l, negative_prompt)
else:
return positive_prompt_g, positive_prompt_l, negative_prompt
accepted_ratios_horizontal = {
"12:5": (1536, 640, 2.400000000),
"7:4": (1344, 768, 1.750000000),
"19:13": (1216, 832, 1.461538462),
"9:7": (1152, 896, 1.285714286)
}
# Vertical aspect ratio
accepted_ratios_vertical = {
"7:9": (896, 1152, 0.777777778),
"13:19": (832, 1216, 0.684210526),
"4:7": (768, 1344, 0.571428571),
"5:12": (640, 1536, 0.416666667)
}
# Square aspect ratio
accepted_ratios_square = {
"1:1": (1024, 1024, 1.00000000)
}
class SDXL_Resolutions:
resolution = ["square - 1024x1024 (1:1)","landscape - 1152x896 (4:3)","landscape - 1216x832 (3:2)","landscape - 1344x768 (16:9)","landscape - 1536x640 (21:9)", "portrait - 896x1152 (3:4)","portrait - 832x1216 (2:3)","portrait - 768x1344 (9:16)","portrait - 640x1536 (9:21)"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"resolution": (s.resolution,),
}
}
RETURN_TYPES = ("INT","INT",)
RETURN_NAMES = ("width", "height")
FUNCTION = "get_resolutions"
CATEGORY="JPS Nodes/Settings"
def get_resolutions(self,resolution):
width = 1024
height = 1024
width = int(width)
height = int(height)
if(resolution == "square - 1024x1024 (1:1)"):
width = 1024
height = 1024
if(resolution == "landscape - 1152x896 (4:3)"):
width = 1152
height = 896
if(resolution == "landscape - 1216x832 (3:2)"):
width = 1216
height = 832
if(resolution == "landscape - 1344x768 (16:9)"):
width = 1344
height = 768
if(resolution == "landscape - 1536x640 (21:9)"):
width = 1536
height = 640
if(resolution == "portrait - 896x1152 (3:4)"):
width = 896
height = 1152
if(resolution == "portrait - 832x1216 (2:3)"):
width = 832
height = 1216
if(resolution == "portrait - 768x1344 (9:16)"):
width = 768
height = 1344
if(resolution == "portrait - 640x1536 (9:21)"):
width = 640
height = 1536
return(int(width),int(height))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Basic_Settings:
resolution = ["Use Image Resolution", "square - 1024x1024 (1:1)","landscape - 1152x896 (4:3)","landscape - 1216x832 (3:2)","landscape - 1344x768 (16:9)","landscape - 1536x640 (21:9)", "portrait - 896x1152 (3:4)","portrait - 832x1216 (2:3)","portrait - 768x1344 (9:16)","portrait - 640x1536 (9:21)"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"resolution": (s.resolution,),
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS,),
"steps_total": ("INT", {"default": 60, "min": 20, "max": 250, "step": 5}),
"base_percentage": ("INT", {"default": 80, "min": 5, "max": 100, "step": 5}),
"cfg": ("FLOAT", {"default": 6.5, "min": 1, "max": 20, "step": 0.1}),
"cfg_rescale": ("FLOAT", {"default": 0.00, "min": 0.00, "max": 1.00, "step": 0.05}),
"cfg_refiner": ("FLOAT", {"default": 6.5, "min": 0, "max": 20, "step": 0.1}),
"ascore_refiner": ("FLOAT", {"default": 6, "min": 1, "max": 10, "step": 0.5}),
"res_factor": ("INT", {"default": 4, "min": 1, "max": 8, "step": 1}),
"clip_skip": ("INT", {"default": -2, "min": -24, "max": -1}),
"filename": ("STRING", {"default": "JPS"}),
}}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("sdxl_basic_settings",)
FUNCTION = "get_values"
CATEGORY="JPS Nodes/Settings"
def get_values(self,resolution,sampler_name,scheduler,steps_total,base_percentage,cfg,cfg_rescale,cfg_refiner,ascore_refiner,res_factor,clip_skip,filename):
width = 1024
height = 1024
width = int(width)
height = int(height)
steps_total = int(steps_total)
step_split = steps_total * base_percentage / 100
cfg = float(cfg)
cfg_rescale = float(cfg_rescale)
cfg_refiner = float (cfg_refiner)
ascore_refiner = float (ascore_refiner)
res_factor = int (res_factor)
base_percentage = int (base_percentage)
image_res = 1
if(resolution == "Use Image Resolution"):
image_res = 2
if(resolution == "square - 1024x1024 (1:1)"):
width = 1024
height = 1024
if(resolution == "landscape - 1152x896 (4:3)"):
width = 1152
height = 896
if(resolution == "landscape - 1216x832 (3:2)"):
width = 1216
height = 832
if(resolution == "landscape - 1344x768 (16:9)"):
width = 1344
height = 768
if(resolution == "landscape - 1536x640 (21:9)"):
width = 1536
height = 640
if(resolution == "portrait - 896x1152 (3:4)"):
width = 896
height = 1152
if(resolution == "portrait - 832x1216 (2:3)"):
width = 832
height = 1216
if(resolution == "portrait - 768x1344 (9:16)"):
width = 768
height = 1344
if(resolution == "portrait - 640x1536 (9:21)"):
width = 640
height = 1536
if(cfg_refiner == 0):
cfg_refiner = cfg
sdxl_basic_settings = width, height, sampler_name, scheduler, steps_total, step_split, cfg, cfg_rescale, cfg_refiner, ascore_refiner, res_factor, clip_skip, filename,image_res
return(sdxl_basic_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Basic_Settings_Pipe:
resolution = ["square - 1024x1024 (1:1)","landscape - 1152x896 (4:3)","landscape - 1216x832 (3:2)","landscape - 1344x768 (16:9)","landscape - 1536x640 (21:9)", "portrait - 896x1152 (3:4)","portrait - 832x1216 (2:3)","portrait - 768x1344 (9:16)","portrait - 640x1536 (9:21)"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"sdxl_basic_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = ("INT","INT","INT",comfy.samplers.KSampler.SAMPLERS,comfy.samplers.KSampler.SCHEDULERS,"INT","INT","FLOAT","FLOAT","FLOAT","FLOAT","INT","INT","STRING",)
RETURN_NAMES = ("image_res","width","height","sampler_name","scheduler","steps_total","step_split","cfg","cfg_rescale","cfg_refiner","ascore_refiner","res_factor","clip_skip","filename",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,sdxl_basic_settings):
width, height, sampler_name, scheduler, steps_total, step_split, cfg, cfg_rescale, cfg_refiner, ascore_refiner, res_factor, clip_skip, filename,image_res = sdxl_basic_settings
return(int(image_res), int(width), int(height), sampler_name, scheduler, int(steps_total), int(step_split), float(cfg), float(cfg_rescale), float(cfg_refiner), float(ascore_refiner), int (res_factor), int(clip_skip), str(filename),)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Settings:
resolution = ["Use Image Resolution", "square - 1024x1024 (1:1)","landscape - 1152x896 (4:3)","landscape - 1216x832 (3:2)","landscape - 1344x768 (16:9)","landscape - 1536x640 (21:9)", "portrait - 896x1152 (3:4)","portrait - 832x1216 (2:3)","portrait - 768x1344 (9:16)","portrait - 640x1536 (9:21)"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"resolution": (s.resolution,),
"res_factor": ("INT", {"default": 4, "min": 1, "max": 8, "step": 1}),
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS,),
"steps": ("INT", {"default": 60, "min": 20, "max": 250, "step": 5}),
"cfg": ("FLOAT", {"default": 6.5, "min": 1, "max": 20, "step": 0.1}),
"cfg_rescale": ("FLOAT", {"default": 0.00, "min": 0.00, "max": 1.00, "step": 0.05}),
"clip_skip": ("INT", {"default": -2, "min": -24, "max": -1}),
"filename": ("STRING", {"default": "JPS"}),
}}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("sdxl_settings",)
FUNCTION = "get_values"
CATEGORY="JPS Nodes/Settings"
def get_values(self,resolution,res_factor,sampler_name,scheduler,steps,cfg,cfg_rescale,clip_skip,filename):
image_res = 1
if(resolution == "Use Image Resolution"):
image_res = 2
width = 1024
height = 1024
if(resolution == "landscape - 1152x896 (4:3)"):
width = 1152
height = 896
if(resolution == "landscape - 1216x832 (3:2)"):
width = 1216
height = 832
if(resolution == "landscape - 1344x768 (16:9)"):
width = 1344
height = 768
if(resolution == "landscape - 1536x640 (21:9)"):
width = 1536
height = 640
if(resolution == "portrait - 896x1152 (3:4)"):
width = 896
height = 1152
if(resolution == "portrait - 832x1216 (2:3)"):
width = 832
height = 1216
if(resolution == "portrait - 768x1344 (9:16)"):
width = 768
height = 1344
if(resolution == "portrait - 640x1536 (9:21)"):
width = 640
height = 1536
sdxl_settings = width, height, res_factor, sampler_name, scheduler, steps, cfg, cfg_rescale, clip_skip, filename,image_res
return(sdxl_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Settings_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"sdxl_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = ("INT","INT","INT","INT",comfy.samplers.KSampler.SAMPLERS,comfy.samplers.KSampler.SCHEDULERS,"INT","FLOAT","FLOAT","INT","STRING",)
RETURN_NAMES = ("image_res","width","height","res_factor","sampler_name","scheduler","steps","cfg","cfg_rescale","clip_skip","filename",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,sdxl_settings):
width, height, res_factor, sampler_name, scheduler, steps, cfg, cfg_rescale, clip_skip, filename,image_res = sdxl_settings
return(int(image_res), int(width), int(height), int (res_factor), sampler_name, scheduler, int(steps), float(cfg), float(cfg_rescale), int(clip_skip), str(filename),)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Prompt_Handling_Plus:
handling = ["Copy to Both if Empty","Use Positive_G + Positive_L","Copy Positive_G to Both","Copy Positive_L to Both","Ignore Positive_G Input", "Ignore Positive_L Input", "Combine Positive_G + Positive_L", "Combine Positive_L + Positive_G",]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"handling": (s.handling,),
"pos_g": ("STRING", {"multiline": True, "placeholder": "Prompt Text pos_g", "dynamicPrompts": True}),
"pos_l": ("STRING", {"multiline": True, "placeholder": "Prompt Text pos_l", "dynamicPrompts": True}),
},
}
RETURN_TYPES = ("STRING","STRING",)
RETURN_NAMES = ("pos_g","pos_l",)
FUNCTION = "pick_handling"
CATEGORY="JPS Nodes/Text"
def pick_handling(self,handling,pos_g,pos_l):
if(handling == "Copy Positive_G to Both"):
pos_l = pos_g
elif(handling == "Copy Positive_L to Both"):
pos_g = pos_l
elif(handling == "Ignore Positive_G Input"):
pos_g = ''
elif(handling == "Ignore Positive_L Input"):
pos_l = ''
elif(handling == "Combine Positive_G + Positive_L"):
combine = pos_g + ' . ' + pos_l
pos_g = combine
pos_l = combine
elif(handling == "Combine Positive_L + Positive_G"):
combine = pos_l + ' . ' + pos_g
pos_g = combine
pos_l = combine
elif(handling == "Copy to Both if Empty" and pos_l == ''):
pos_l = pos_g
elif(handling == "Copy to Both if Empty" and pos_g == ''):
pos_g = pos_l
return(pos_g,pos_l,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Text_Prompt:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING", {"multiline": True, "placeholder": "Prompt Text", "dynamicPrompts": True}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("text",)
FUNCTION = "text_prompt"
CATEGORY="JPS Nodes/Text"
def text_prompt(self,text):
return(text,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Text_Prompt_Combo:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"pos": ("STRING", {"multiline": True, "placeholder": "Prompt Text Positive", "dynamicPrompts": True}),
"neg": ("STRING", {"multiline": True, "placeholder": "Prompt Text Negative", "dynamicPrompts": True}),
},
}
RETURN_TYPES = ("STRING","STRING",)
RETURN_NAMES = ("pos","neg",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Text"
def give_values(self,pos,neg):
return(pos,neg,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Prompt_Handling:
handling = ["Copy to Both if Empty","Use Positive_G + Positive_L","Copy Positive_G to Both","Copy Positive_L to Both","Ignore Positive_G Input", "Ignore Positive_L Input", "Combine Positive_G + Positive_L", "Combine Positive_L + Positive_G",]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"handling": (s.handling,),
"pos_g": ("STRING", {"default": ""}),
"pos_l": ("STRING", {"default": ""}),
},
}
RETURN_TYPES = ("STRING","STRING",)
RETURN_NAMES = ("pos_g","pos_l",)
FUNCTION = "pick_handling"
CATEGORY="JPS Nodes/Text"
def pick_handling(self,handling,pos_g,pos_l,):
if(handling == "Copy Positive_G to Both"):
pos_l = pos_g
elif(handling == "Copy Positive_L to Both"):
pos_g = pos_l
elif(handling == "Ignore Positive_G Input"):
pos_g = ''
elif(handling == "Ignore Positive_L Input"):
pos_l = ''
elif(handling == "Combine Positive_G + Positive_L"):
combine = pos_g + ' . ' + pos_l
pos_g = combine
pos_l = combine
elif(handling == "Combine Positive_L + Positive_G"):
combine = pos_l + ' . ' + pos_g
pos_g = combine
pos_l = combine
elif(handling == "Copy to Both if Empty" and pos_l == ''):
pos_l = pos_g
elif(handling == "Copy to Both if Empty" and pos_g == ''):
pos_g = pos_l
return(pos_g,pos_l,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Math_Resolution_Multiply:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"width": ("INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}),
"height": ("INT", {"default": 1024, "min": 256, "max": 8192, "step": 16}),
"factor": ("INT", {"default": 2, "min": 1, "max": 8, "step": 1}),
}}
RETURN_TYPES = ("INT","INT")
RETURN_NAMES = ("width_resized", "height_resized")
FUNCTION = "get_newres"
CATEGORY="JPS Nodes/Math"
def get_newres(self,width,height,factor):
factor = int(factor)
width = int(width)
width_resized = int(width) * int(factor)
height = int(height)
height_resized = int (height) * int(factor)
return(int(width_resized),int(height_resized))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Math_Largest_Integer:
def init(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"int_a": ("INT", {"default": 1,}),
"int_b": ("INT", {"default": 1,}),
}
}
RETURN_TYPES = ("INT","INT","INT")
RETURN_NAMES = ("larger_int","smaller_int","is_a_larger")
FUNCTION = "get_lrg"
CATEGORY="JPS Nodes/Math"
def get_lrg(self,int_a,int_b):
larger_int = int(int_b)
smaller_int = int(int_a)
is_a_larger = int(0)
if int_a > int_b:
larger_int = int(int_a)
smaller_int = int(int_b)
is_a_larger = int(1)
return(int(larger_int),int(smaller_int),int(is_a_larger))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Math_Multiply_INT_INT:
def init(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"int_a": ("INT", {"default": 1,}),
"int_b": ("INT", {"default": 1,}),
}
}
RETURN_TYPES = ("INT","FLOAT")
RETURN_NAMES = ("int_multiply","float_multiply")
FUNCTION = "get_multiply_int_int"
CATEGORY="JPS Nodes/Math"
def get_multiply_int_int(self,int_a,int_b):
int_multiply = int(int_a) * int(int_b)
float_multiply = int(int_a) * int(int_b)
return(int(int_multiply),float(float_multiply))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Math_Multiply_INT_FLOAT:
def init(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"int_a": ("INT", {"default": 1,}),
"float_b": ("FLOAT", {"default": 1,}),
}
}
RETURN_TYPES = ("INT","FLOAT")
RETURN_NAMES = ("int_multiply","float_multiply")
FUNCTION = "get_multiply_int_float"
CATEGORY="JPS Nodes/Math"
def get_multiply_int_float(self,int_a,float_b):
int_multiply = int(int_a) * float(float_b)
float_multiply = int(int_a) * float(float_b)
return(int(int_multiply),float(float_multiply))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Math_Multiply_FLOAT_FLOAT:
def init(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"float_a": ("FLOAT", {"default": 1,}),
"float_b": ("FLOAT", {"default": 1,}),
}
}
RETURN_TYPES = ("INT","FLOAT")
RETURN_NAMES = ("int_multiply","float_multiply")
FUNCTION = "get_multiply_float_float"
CATEGORY="JPS Nodes/Math"
def get_multiply_float_float(self,float_a,float_b):
int_multiply = float(float_a) * float(float_b)
float_multiply = float(float_a) * float(float_b)
return(int(int_multiply),float(float_multiply))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Math_Substract_INT_INT:
def init(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"int_a": ("INT", {"default": 1,}),
"int_b": ("INT", {"default": 1,}),
}
}
RETURN_TYPES = ("INT","FLOAT")
RETURN_NAMES = ("int_substract","float_substract")
FUNCTION = "get_substract_int_int"
CATEGORY="JPS Nodes/Math"
def get_substract_int_int(self,int_a,int_b):
int_substract = int(int_a) - int(int_b)
float_substract = int(int_a) - int(int_b)
return(int(int_substract),float(float_substract))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Text_Concatenate:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"delimiter": (["none", "space", "comma"],),
},
"optional": {
"text1": ("STRING", {"forceInput": True}),
"text2": ("STRING", {"forceInput": True}),
"text3": ("STRING", {"forceInput": True}),
"text4": ("STRING", {"forceInput": True}),
"text5": ("STRING", {"forceInput": True}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("text",)
FUNCTION = "get_contxt"
CATEGORY = "JPS Nodes/Text"
def get_contxt(self, delimiter, text1=None, text2=None, text3=None, text4=None, text5=None):
needdelim = False
delim = ""
if delimiter == "space":
delim = " "
if delimiter == "comma":
delim = ", "
concatenated = ""
if text1:
concatenated = text1
needdelim = True
if text2:
if needdelim:
concatenated += delim
concatenated += text2
needdelim = True
if text3:
if needdelim:
concatenated += delim
concatenated += text3
needdelim = True
if text4:
if needdelim:
concatenated += delim
concatenated += text4
needdelim = True
if text5:
if needdelim:
concatenated += delim
concatenated += text5
needdelim = True
return (concatenated,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Get_Date_Time_String:
time_format = ["%Y%m%d%H%M%S","%Y%m%d%H%M","%Y%m%d","%Y-%m-%d-%H_%M_%S","%Y-%m-%d-%H_%M","%Y-%m-%d","%Y-%m-%d %H_%M_%S","%Y-%m-%d %H_%M","%Y-%m-%d","%H%M","%H%M%S","%H_%M","%H_%M_%S"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"style": (s.time_format,),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("time_format",)
FUNCTION = "get_time"
CATEGORY = "JPS Nodes/Text"
def get_time(self, style):
now = datetime.now()
timestamp = now.strftime(style)
return (timestamp,)
@classmethod
def IS_CHANGED(s, style):
now = datetime.now()
timestamp = now.strftime(style)
return (timestamp,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Time_Seed:
# time_format = ["%Y%m%d%H%M%S","%Y%m%d%H%M","%Y%m%d","%Y-%m-%d-%H_%M_%S","%Y-%m-%d-%H_%M","%Y-%m-%d","%Y-%m-%d %H_%M_%S","%Y-%m-%d %H_%M","%Y-%m-%d","%H%M","%H%M%S","%H_%M","%H_%M_%S"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"fixed_seed": ("INT", {"default": 0, "min": 0, "max": 99999999999, "step": 1}),
}
}
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("seed",)
FUNCTION = "get_seed"
CATEGORY = "JPS Nodes/Text"
def get_seed(self, fixed_seed):
now = datetime.now()
time = now.strftime("%Y%m%d%H%M%S")
seed_out = int(time) + np.random.randint(999999)
if fixed_seed != 0:
seed_out=fixed_seed
return (int(seed_out),)
@classmethod
def IS_CHANGED(s, seed_out):
now = datetime.now()
forceupdate = now.strftime("%Y%m%d%H%M%S")
forceupdate = forceupdate + np.random.randint(99999999) + seed_out
return (forceupdate,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Recommended_Resolution_Calc:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"target_width": ("INT", {
"default": 1024,
"min": 0,
"max": 8192,
"step": 2
}),
"target_height": ("INT", {
"default": 1024,
"min": 0,
"max": 8192,
"step": 2
}),
},
}
RETURN_TYPES = ("INT","INT",)
RETURN_NAMES = ("SDXL_width","SDXL_height",)
FUNCTION = "calcSDXLres"
CATEGORY = "JPS Nodes/Math"
def calcSDXLres(self, target_width, target_height):
target_ratio = target_width / target_height
closest_ratio = None
closest_diff = float('inf')
for ratio, (x_size, y_size, num_ratio) in accepted_ratios_horizontal.items():
diff = abs(num_ratio - target_ratio)
if diff < closest_diff:
closest_ratio = ratio
closest_diff = diff
for ratio, (x_size, y_size, num_ratio) in accepted_ratios_vertical.items():
diff = abs(num_ratio - target_ratio)
if diff < closest_diff:
closest_ratio = ratio
closest_diff = diff
# Compare with square aspect ratio
x_size, y_size, num_ratio = accepted_ratios_square["1:1"]
diff = abs(num_ratio - target_ratio)
if diff < closest_diff:
closest_ratio = "1:1"
if closest_ratio in accepted_ratios_horizontal:
SDXL_width, SDXL_height, _ = accepted_ratios_horizontal[closest_ratio]
elif closest_ratio in accepted_ratios_vertical:
SDXL_width, SDXL_height, _ = accepted_ratios_vertical[closest_ratio]
else:
SDXL_width, SDXL_height, _ = accepted_ratios_square[closest_ratio]
return (SDXL_width, SDXL_height)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Generation_TXT_IMG_Settings:
mode = ["Txt2Img","Img2Img"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"mode": (s.mode,),
"img_percentage": ("INT", {"default": 50, "min": 0, "max": 100, "step": 5}),
}
}
RETURN_TYPES = ("INT","FLOAT",)
RETURN_NAMES = ("gen_mode", "img_strength")
FUNCTION = "get_genmode"
CATEGORY="JPS Nodes/Settings"
def get_genmode(self,mode,img_percentage):
gen_mode = 1
img_strength = 0
if(mode == "Txt2Img"):
gen_mode = int(1)
img_strength = 0.001
if(mode == "Img2Img"):
gen_mode = int(2)
img_strength = img_percentage / 100
return(int(gen_mode),float(img_strength))
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CropImage_Settings:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"source_crop_pos": (["center","top", "bottom", "left", "right"],),
"source_crop_offset": ("INT", { "default": 0, "min": -2048, "max": 2048, "step": 1, "display": "number" }),
"support_crop_pos": (["center","top", "bottom", "left", "right"],),
"support_crop_offset": ("INT", { "default": 0, "min": -2048, "max": 2048, "step": 1, "display": "number" }),
"crop_intpol": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("cropimage_settings",)
FUNCTION = "get_cropimage"
CATEGORY="JPS Nodes/Settings"
def get_cropimage(self, source_crop_pos, source_crop_offset, support_crop_pos, support_crop_offset, crop_intpol,):
cropimage_settings = source_crop_pos, source_crop_offset, support_crop_pos, support_crop_offset, crop_intpol
return(cropimage_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CropImage_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"cropimage_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = (["center","top", "bottom", "left", "right"],"INT",["center","top", "bottom", "left", "right"],"INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],)
RETURN_NAMES = ("source_crop_pos", "source_crop_offset", "support_crop_pos", "support_crop_offset", "crop_intpol",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,cropimage_settings):
source_crop_pos, source_crop_offset, support_crop_pos, support_crop_offset, crop_intpol = cropimage_settings
return(source_crop_pos, source_crop_offset, support_crop_pos, support_crop_offset, crop_intpol,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class ImageToImage_Settings:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"img2img_strength": ("INT", {"default": 50, "min": 0, "max": 100, "step": 1}),
"inpaint_strength": ("INT", {"default": 100, "min": 2, "max": 100, "step": 1}),
"inpaint_grow_mask": ("INT", {"default": 20, "min": 0, "max": 200, "step": 2}),
"unsampler_strength": ("INT", {"default": 30, "min": 0, "max": 100, "step": 1}),
"unsampler_cfg": ("FLOAT", {"default": 1, "min": 1, "max": 10, "step": 0.1}),
"unsampler_sampler": (comfy.samplers.KSampler.SAMPLERS,),
"unsampler_scheduler": (comfy.samplers.KSampler.SCHEDULERS,),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("img2img_settings",)
FUNCTION = "get_img2img"
CATEGORY="JPS Nodes/Settings"
def get_img2img(self, img2img_strength, inpaint_strength, inpaint_grow_mask, unsampler_strength, unsampler_cfg, unsampler_sampler, unsampler_scheduler,):
img2img_strength = (img2img_strength + 0.001) / 100
inpaint_strength = (100 - inpaint_strength + 0.001) / 100
unsampler_strength = (unsampler_strength + 0.001) / 100
img2img_settings = img2img_strength, inpaint_strength, inpaint_grow_mask, unsampler_strength, unsampler_cfg, unsampler_sampler, unsampler_scheduler
return(img2img_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class ImageToImage_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"img2img_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = ("FLOAT", "FLOAT", "INT", "FLOAT", "FLOAT", comfy.samplers.KSampler.SAMPLERS, comfy.samplers.KSampler.SCHEDULERS,)
RETURN_NAMES = ("img2img_strength", "inpaint_strength", "inpaint_grow_mask", "unsampler_strength", "unsampler_cfg", "unsampler_sampler", "unsampler_scheduler",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,img2img_settings):
img2img_strength, inpaint_strength, inpaint_grow_mask, unsampler_strength, unsampler_cfg, unsampler_sampler, unsampler_scheduler = img2img_settings
return(img2img_strength, inpaint_strength, inpaint_grow_mask, unsampler_strength, unsampler_cfg, unsampler_sampler, unsampler_scheduler,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_CannyEdge_Settings:
cannyedgefrom = ["Source Image", "Support Image", "Support Direct"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"cannyedge_from": (s.cannyedgefrom,),
"cannyedge_strength": ("FLOAT", {"default": 1.00, "min": 0.00, "max": 10.00, "step": 0.10}),
"cannyedge_start": ("FLOAT", {"default": 0.000, "min": 0.000, "max": 1.000, "step": 0.05}),
"cannyedge_end": ("FLOAT", {"default": 1.000, "min": 0.000, "max": 1.000, "step": 0.05}),
"cannyedge_low": ("INT", {"default": 100, "min": 0, "max": 255, "step": 1}),
"cannyedge_high": ("INT", {"default": 200, "min": 0, "max": 255, "step": 1}),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("cannyedge_settings",)
FUNCTION = "get_ctrlnet_cannyedge"
CATEGORY="JPS Nodes/Settings"
def get_ctrlnet_cannyedge(self, cannyedge_from, cannyedge_strength, cannyedge_start, cannyedge_end, cannyedge_low, cannyedge_high):
cannyedge_source = int (1)
if (cannyedge_from == "Support Image"):
cannyedge_source = int(2)
if (cannyedge_from == "Support Direct"):
cannyedge_source = int(3)
cannyedge_settings = cannyedge_source, cannyedge_strength, cannyedge_start, cannyedge_end, cannyedge_low, cannyedge_high
return(cannyedge_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_CannyEdge_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"cannyedge_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = ("INT", "FLOAT", "FLOAT", "FLOAT", "INT", "INT", )
RETURN_NAMES = ("cannyedge_source", "cannyedge_strength", "cannyedge_start", "cannyedge_end", "cannyedge_low", "cannyedge_high",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,cannyedge_settings):
cannyedge_source, cannyedge_strength, cannyedge_start, cannyedge_end, cannyedge_low, cannyedge_high = cannyedge_settings
return(cannyedge_source, cannyedge_strength, cannyedge_start, cannyedge_end, cannyedge_low, cannyedge_high,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_OpenPose_Settings:
openposefrom = ["Source Image", "Support Image", "Support Direct"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"openpose_from": (s.openposefrom,),
"openpose_strength": ("FLOAT", {"default": 1.00, "min": 0.00, "max": 10.00, "step": 0.10}),
"openpose_start": ("FLOAT", {"default": 0.000, "min": 0.000, "max": 1.000, "step": 0.05}),
"openpose_end": ("FLOAT", {"default": 1.000, "min": 0.000, "max": 1.000, "step": 0.05}),
"openpose_body": (["enable","disable"],),
"openpose_face": (["enable","disable"],),
"openpose_hand": (["enable","disable"],),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("openpose_settings",)
FUNCTION = "get_ctrlnet_openpose"
CATEGORY="JPS Nodes/Settings"
def get_ctrlnet_openpose(self, openpose_from, openpose_strength, openpose_start, openpose_end, openpose_body, openpose_face, openpose_hand):
openpose_source = int (1)
if (openpose_from == "Support Image"):
openpose_source = int(2)
if (openpose_from == "Support Direct"):
openpose_source = int(3)
openpose_settings = openpose_source, openpose_strength, openpose_start, openpose_end, openpose_body, openpose_face, openpose_hand
return(openpose_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_OpenPose_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"openpose_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = ("INT", "FLOAT", "FLOAT", "FLOAT", ["enable","disable"], ["enable","disable"], ["enable","disable"],)
RETURN_NAMES = ("openpose_source", "openpose_strength", "openpose_start", "openpose_end", "openpose_body", "openpose_face", "openpose_hand",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,openpose_settings):
openpose_source, openpose_strength, openpose_start, openpose_end, openpose_body, openpose_face, openpose_hand = openpose_settings
return(openpose_source, openpose_strength, openpose_start, openpose_end, openpose_body, openpose_face, openpose_hand,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_MiDaS_Settings:
midasfrom = ["Source Image", "Support Image", "Support Direct"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"midas_from": (s.midasfrom,),
"midas_strength": ("FLOAT", {"default": 1.00, "min": 0.00, "max": 10.00, "step": 0.10}),
"midas_start": ("FLOAT", {"default": 0.000, "min": 0.000, "max": 1.000, "step": 0.05}),
"midas_end": ("FLOAT", {"default": 1.000, "min": 0.000, "max": 1.000, "step": 0.05}),
"midas_a": ("FLOAT", {"default": 6.28, "min": 0.00, "max": 15.71, "step": 0.05}),
"midas_bg": ("FLOAT", {"default": 0.10, "min": 0.00, "max": 1.00, "step": 0.05}),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("midas_settings",)
FUNCTION = "get_ctrlnet_midas"
CATEGORY="JPS Nodes/Settings"
def get_ctrlnet_midas(self, midas_from, midas_strength, midas_start, midas_end, midas_a, midas_bg):
midas_source = int (1)
if (midas_from == "Support Image"):
midas_source = int(2)
if (midas_from == "Support Direct"):
midas_source = int(3)
midas_settings = midas_source, midas_strength, midas_start, midas_end, midas_a, midas_bg
return(midas_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_MiDaS_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"midas_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = ("INT", "FLOAT", "FLOAT", "FLOAT", "FLOAT", "FLOAT",)
RETURN_NAMES = ("midas_source", "midas_strength", "midas_start", "midas_end", "midas_a", "midas_bg",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,midas_settings):
midas_source, midas_strength, midas_start, midas_end, midas_a, midas_bg = midas_settings
return(midas_source, midas_strength, midas_start, midas_end, midas_a, midas_bg,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_ZoeDepth_Settings:
zoefrom = ["Source Image", "Support Image", "Support Direct"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"zoe_from": (s.zoefrom,),
"zoe_strength": ("FLOAT", {"default": 1.00, "min": 0.00, "max": 10.00, "step": 0.10}),
"zoe_start": ("FLOAT", {"default": 0.000, "min": 0.000, "max": 1.000, "step": 0.05}),
"zoe_end": ("FLOAT", {"default": 1.000, "min": 0.000, "max": 1.000, "step": 0.05}),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("zoedepth_settings",)
FUNCTION = "get_ctrlnet_zoedepth"
CATEGORY="JPS Nodes/Settings"
def get_ctrlnet_zoedepth(self, zoe_from, zoe_strength, zoe_start, zoe_end):
zoe_source = int (1)
if (zoe_from == "Support Image"):
zoe_source = int(2)
if (zoe_from == "Support Direct"):
zoe_source = int(3)
zoedepth_settings = zoe_source, zoe_strength, zoe_start, zoe_end
return(zoedepth_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CtrlNet_ZoeDepth_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"zoedepth_settings": ("BASIC_PIPE",)
},
}
RETURN_TYPES = ("INT", "FLOAT", "FLOAT", "FLOAT",)
RETURN_NAMES = ("zoe_source", "zoe_strength", "zoe_start", "zoe_end",)
FUNCTION = "give_values"
CATEGORY="JPS Nodes/Pipes"
def give_values(self,zoedepth_settings):
zoe_source, zoe_strength, zoe_start, zoe_end = zoedepth_settings
return(zoe_source, zoe_strength, zoe_start, zoe_end,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class IP_Adapter_Settings:
ipamasktype = ["No Mask","Mask Editor","Mask Editor (inverted)","Red from Image","Green from Image","Blue from Image"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ipa_weight": ("FLOAT", {"default": 0.5, "min": 0, "max": 3, "step": 0.01}),
"ipa_wtype": (["linear", "ease in", "ease out", "ease in-out", "reverse in-out", "weak input", "weak output", "weak middle", "strong middle"],),
"ipa_noise": ("FLOAT", {"default": 0.0, "min": 0, "max": 1, "step": 0.05}),
"ipa_start": ("FLOAT", {"default": 0.00, "min": 0, "max": 1, "step": 0.05}),
"ipa_stop": ("FLOAT", {"default": 1.00, "min": 0, "max": 1, "step": 0.05}),
"ipa_crop": (["center","top", "bottom", "left", "right"],),
"ipa_zoom": ("FLOAT", { "default": 1, "min": 1, "max": 5, "step": 0.1, "display": "number" }),
"ipa_offset_x": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"ipa_offset_y": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"ipa_mask": (s.ipamasktype,),
"crop_intpol": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", { "default": 0.0, "min": 0, "max": 1, "step": 0.05, "display": "number" }),
"ipa_model": (["SDXL ViT-H", "SDXL Plus ViT-H", "SDXL Plus Face ViT-H"],),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("ip_adapter_single_settings",)
FUNCTION = "get_ipamodesingle"
CATEGORY="JPS Nodes/Settings"
def get_ipamodesingle(self,ipa_weight,ipa_wtype,ipa_noise,ipa_start,ipa_stop,ipa_crop,ipa_zoom,ipa_offset_x,ipa_offset_y,ipa_mask,crop_intpol,sharpening,ipa_model):
ipamask = int(0)
if(ipa_mask == "Mask Editor"):
ipamask = int(1)
elif(ipa_mask == "Mask Editor (inverted)"):
ipamask = int(2)
elif(ipa_mask == "Red from Image"):
ipamask = int(3)
elif(ipa_mask == "Green from Image"):
ipamask = int(4)
elif(ipa_mask == "Blue from Image"):
ipamask = int(5)
ipamodel = int (0)
if(ipa_model == "SDXL ViT-H"):
ipamodel = int(1)
elif(ipa_model == "SDXL Plus ViT-H"):
ipamodel = int(2)
elif(ipa_model == "SDXL Plus Face ViT-H"):
ipamodel = int(3)
ipaweight = ipa_weight
ipawtype = ipa_wtype
ipanoise = ipa_noise
ipastart = ipa_start
ipastop = ipa_stop
ipacrop = ipa_crop
ipazoom = ipa_zoom
ipaoffsetx = ipa_offset_x
ipaoffsety = ipa_offset_y
cropintpol = crop_intpol
ip_adapter_settings = ipaweight,ipawtype,ipanoise,ipastart,ipastop,ipacrop,ipazoom,ipaoffsetx,ipaoffsety,ipamask,cropintpol,sharpening,ipamodel
return(ip_adapter_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class IP_Adapter_Settings_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ip_adapter_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("FLOAT",["linear", "ease in", "ease out", "ease in-out", "reverse in-out", "weak input", "weak output", "weak middle", "strong middle"],"FLOAT","FLOAT","FLOAT",["center","top", "bottom", "left", "right"],"FLOAT","INT","INT","INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],"FLOAT","INT")
RETURN_NAMES = ("ipa_weight","ipa_wtype","ipa_noise","ipa_start","ipa_stop","ipa_crop","ipa_zoom","ipa_offset_x","ipa_offset_y","ipa_mask","crop_intpol","sharpening","ipa_model")
FUNCTION = "get_ipamode_single"
CATEGORY="JPS Nodes/Pipes"
def get_ipamode_single(self,ip_adapter_settings):
ipaweight,ipawtype,ipanoise,ipastart,ipastop,ipacrop,ipazoom,ipaoffsetx,ipaoffsety,ipamask,cropintpol,sharpening,ipamodel = ip_adapter_settings
return(float(ipaweight),ipawtype,float(ipanoise),float(ipastart),float(ipastop),ipacrop,float(ipazoom),int(ipaoffsetx),int(ipaoffsety),int(ipamask),cropintpol,float(sharpening),int(ipamodel),)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class IP_Adapter_Tiled_Settings:
preparetypes = ["Target AR + Target Res", "Target AR + Tile Res", "Tile AR + Target Res", "Source AR + Source Res", "Source AR + Tile Res", "Tile AR + Source Res", "Square AR + Target Res", "Square AR + Tile Res", "Direct Source" ]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ipa_model": (["SDXL ViT-H", "SDXL Plus ViT-H", "SDXL Plus Face ViT-H"],),
"ipa_wtype": (["linear", "ease in", "ease out", "ease in-out", "reverse in-out", "weak input", "weak output", "weak middle", "strong middle"],),
"ipa_weight": ("FLOAT", {"default": 0.5, "min": 0, "max": 3, "step": 0.01}),
"ipa_noise": ("FLOAT", {"default": 0.0, "min": 0, "max": 1, "step": 0.05}),
"ipa_start": ("FLOAT", {"default": 0.00, "min": 0, "max": 1, "step": 0.05}),
"ipa_end": ("FLOAT", {"default": 1.00, "min": 0, "max": 1, "step": 0.05}),
"tile_short": ("INT", { "default": 2, "min": 1, "max": 5, "step": 1, "display": "number" }),
"tile_weight": ("FLOAT", {"default": 0.55, "min": 0, "max": 1, "step": 0.05}),
"zoom": ("INT", {"default": 100, "min": 1, "max": 500, "step": 1}),
"offset_w": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"offset_h": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"prepare_type": (s.preparetypes,),
"prepare_intpol": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"prepare_sharpening": ("FLOAT", { "default": 0.0, "min": 0, "max": 1, "step": 0.05, "display": "number" }),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("ip_adapter_tiled_settings",)
FUNCTION = "get_ipatiled"
CATEGORY="JPS Nodes/Settings"
def get_ipatiled(self,ipa_model,ipa_wtype,ipa_weight,ipa_noise,ipa_start,ipa_end,tile_short,tile_weight,zoom,offset_w,offset_h,prepare_type,prepare_intpol,prepare_sharpening,):
ipamodel = int (0)
if(ipa_model == "SDXL ViT-H"):
ipamodel = int(1)
elif(ipa_model == "SDXL Plus ViT-H"):
ipamodel = int(2)
elif(ipa_model == "SDXL Plus Face ViT-H"):
ipamodel = int(3)
preparetype = int (0)
if(prepare_type == "Target AR + Target Res"):
preparetype = int(1)
elif(prepare_type == "Target AR + Tile Res"):
preparetype = int(2)
elif(prepare_type == "Tile AR + Target Res"):
preparetype = int(3)
elif(prepare_type == "Source AR + Source Res"):
preparetype = int(4)
elif(prepare_type == "Source AR + Tile Res"):
preparetype = int(5)
elif(prepare_type == "Tile AR + Source Res"):
preparetype = int(6)
elif(prepare_type == "Square AR + Target Res"):
preparetype = int(7)
elif(prepare_type == "Square AR + Tile Res"):
preparetype = int(8)
elif(prepare_type == "Direct Source"):
preparetype = int(9)
ip_adapter_settings = ipamodel,ipa_wtype,ipa_weight,ipa_noise,ipa_start,ipa_end,tile_short,tile_weight,zoom,offset_w,offset_h,preparetype,prepare_intpol,prepare_sharpening
return(ip_adapter_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class IP_Adapter_Tiled_Settings_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ip_adapter_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("INT",["linear", "ease in", "ease out", "ease in-out", "reverse in-out", "weak input", "weak output", "weak middle", "strong middle"],"FLOAT","FLOAT","FLOAT","FLOAT","INT","FLOAT","INT","INT","INT","INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],"FLOAT")
RETURN_NAMES = ("ipa_model","ipa_wtype","ipa_weight","ipa_noise","ipa_start","ipa_end","tile_short","tile_weight","zoom","offset_w","offset_h","prepare_type","prepare_intpol","prepare_sharpening")
FUNCTION = "get_ipatiled"
CATEGORY="JPS Nodes/Pipes"
def get_ipatiled(self,ip_adapter_settings):
ipamodel,ipa_wtype,ipa_weight,ipa_noise,ipa_start,ipa_end,tile_short,tile_weight,zoom,offset_w,offset_h,preparetype,prepare_intpol,prepare_sharpening = ip_adapter_settings
return(ipamodel,ipa_wtype,ipa_weight,ipa_noise,ipa_start,ipa_end,tile_short,tile_weight,zoom,offset_w,offset_h,preparetype,prepare_intpol,prepare_sharpening)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantID_Settings:
ipamasktype = ["No Mask","Mask Editor","Mask Editor (inverted)","Red from Image","Green from Image","Blue from Image"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"ip_weight": ("FLOAT", {"default": 0.8, "min": 0, "max": 1, "step": 0.01}),
"cn_strength": ("FLOAT", {"default": 0.65, "min": 0, "max": 10, "step": 0.01}),
"noise": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.1, }),
"start": ("FLOAT", {"default": 0.00, "min": 0, "max": 1, "step": 0.05}),
"end": ("FLOAT", {"default": 1.00, "min": 0, "max": 1, "step": 0.05}),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("instantid_settings",)
FUNCTION = "get_instantid"
CATEGORY="JPS Nodes/Settings"
def get_instantid(self,ip_weight,cn_strength,noise,start,end):
instantid_settings = ip_weight,cn_strength,noise,start,end
return(instantid_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantID_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"instantid_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("FLOAT","FLOAT","FLOAT","FLOAT","FLOAT",)
RETURN_NAMES = ("ip_weight","cn_strength","noise","start","end",)
FUNCTION = "get_instantid"
CATEGORY="JPS Nodes/Pipes"
def get_instantid(self,instantid_settings):
ip_weight,cn_strength,noise,start,end = instantid_settings
return(ip_weight,cn_strength,noise,start,end)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class ImagePrepare_Settings:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"offset_width": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"offset_height": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"crop_left": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_right": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_top": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_bottom": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"padding_left": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_right": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_top": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_bottom": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", { "default": 0.0, "min": 0, "max": 1, "step": 0.05, "display": "number" }),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("imageprepare_settings",)
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Settings"
def get_imageprepare(self,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening):
imageprepare_settings = offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening
return(imageprepare_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class ImagePrepare_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"imageprepare_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("INT","INT","INT","INT","INT","INT","INT","INT","INT","INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],"FLOAT",)
RETURN_NAMES = ("offset_width","offset_height","crop_left","crop_right","crop_top","crop_bottom","padding_left","padding_right","padding_top","padding_bottom","interpolation","sharpening",)
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Pipes"
def get_imageprepare(self,imageprepare_settings):
offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening = imageprepare_settings
return(offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantIDSourcePrepare_Settings:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"resize_to": (["Resize to Target","Keep Size"],),
"offset_width": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"offset_height": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"crop_left": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_right": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_top": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_bottom": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", { "default": 0.0, "min": 0, "max": 1, "step": 0.05, "display": "number" }),
"flip": (["No", "X-Axis", "Y-Axis"],),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("imageprepare_settings",)
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Settings"
def get_imageprepare(self,resize_to,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,interpolation,sharpening,flip):
resizeto = int (0)
if(resize_to == "Keep Size"):
resizeto = int(1)
elif(resize_to == "Resize to Target"):
resizeto = int(2)
imageprepare_settings = resizeto, offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,interpolation,sharpening,flip
return(imageprepare_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantIDSourcePrepare_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"imageprepare_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("INT","INT","INT","INT","INT","INT","INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],"FLOAT",["No", "X-Axis", "Y-Axis"],)
RETURN_NAMES = ("resize_to","offset_width","offset_height","crop_left","crop_right","crop_top","crop_bottom","interpolation","sharpening","flip",)
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Pipes"
def get_imageprepare(self,imageprepare_settings):
resizeto,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,interpolation,sharpening,flip = imageprepare_settings
return(resizeto,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,interpolation,sharpening,flip)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantIDPosePrepare_Settings:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"resize_to": (["Resize to Target","Resize to Source","Keep Size"],),
"offset_width": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"offset_height": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"crop_left": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_right": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_top": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_bottom": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"padding_left": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_right": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_top": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_bottom": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", { "default": 0.0, "min": 0, "max": 1, "step": 0.05, "display": "number" }),
"flip": (["No", "X-Axis", "Y-Axis"],),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("imageprepare_settings",)
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Settings"
def get_imageprepare(self,resize_to,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening,flip):
resizeto = int (0)
if(resize_to == "Keep Size"):
resizeto = int(1)
elif(resize_to == "Resize to Target"):
resizeto = int(2)
elif(resize_to == "Resize to Source"):
resizeto = int(3)
imageprepare_settings = resizeto, offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening,flip
return(imageprepare_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantIDPosePrepare_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"imageprepare_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("INT","INT","INT","INT","INT","INT","INT","INT","INT","INT","INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],"FLOAT",["No", "X-Axis", "Y-Axis"],)
RETURN_NAMES = ("resize_to","offset_width","offset_height","crop_left","crop_right","crop_top","crop_bottom","padding_left","padding_right","padding_top","padding_bottom","interpolation","sharpening","flip")
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Pipes"
def get_imageprepare(self,imageprepare_settings):
resizeto,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening,flip = imageprepare_settings
return(resizeto,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening,flip)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantIDMaskPrepare_Settings:
masktypes = ["No Mask","Mask Editor","Mask Editor (inverted)","Red from Image","Green from Image","Blue from Image"]
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"mask_type": (s.masktypes,),
"resize_to": (["Resize to Target","Resize to Source","Keep Size"],),
"resize_type": (["Crop","Stretch"],),
"offset_width": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"offset_height": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"crop_left": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_right": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_top": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_bottom": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"padding_left": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_right": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_top": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_bottom": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", { "default": 0.0, "min": 0, "max": 1, "step": 0.05, "display": "number" }),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("imageprepare_settings",)
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Settings"
def get_imageprepare(self,mask_type,resize_to,resize_type,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening):
resizeto = int (0)
if(resize_to == "Keep Size"):
resizeto = int(1)
elif(resize_to == "Resize to Target"):
resizeto = int(2)
elif(resize_to == "Resize to Source"):
resizeto = int(3)
resizetype = "Crop"
if(resize_type == "Stretch"):
resizetype = "Stretch"
masktype = int(0)
if(mask_type == "Mask Editor"):
masktype = int(1)
elif(mask_type == "Mask Editor (inverted)"):
masktype = int(2)
elif(mask_type == "Red from Image"):
masktype = int(3)
elif(mask_type == "Green from Image"):
masktype = int(4)
elif(mask_type == "Blue from Image"):
masktype = int(5)
imageprepare_settings = masktype, resizeto, resizetype, offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening
return(imageprepare_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class InstantIDMaskPrepare_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"imageprepare_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("INT","INT",["Crop","Stretch"],"INT","INT","INT","INT","INT","INT","INT","INT","INT","INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],"FLOAT",)
RETURN_NAMES = ("mask_type","resize_to","resize_type","offset_width","offset_height","crop_left","crop_right","crop_top","crop_bottom","padding_left","padding_right","padding_top","padding_bottom","interpolation","sharpening",)
FUNCTION = "get_imageprepare"
CATEGORY="JPS Nodes/Pipes"
def get_imageprepare(self,imageprepare_settings):
masktype,resizeto,resizetype,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening = imageprepare_settings
return(masktype,resizeto,resizetype,offset_width,offset_height,crop_left,crop_right,crop_top,crop_bottom,padding_left,padding_right,padding_top,padding_bottom,interpolation,sharpening)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Revision_Settings:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"rev1_strength": ("FLOAT", {"default": 1, "min": 0, "max": 10, "step": 0.1}),
"rev2_strength": ("FLOAT", {"default": 1, "min": 0, "max": 10, "step": 0.1}),
"rev1_noiseaug": ("FLOAT", {"default": 0, "min": 0, "max": 1, "step": 0.1}),
"rev2_noiseaug": ("FLOAT", {"default": 0, "min": 0, "max": 1, "step": 0.1}),
"rev1_crop": (["center","top", "bottom", "left", "right"],),
"rev1_offset": ("INT", { "default": 0, "min": -2048, "max": 2048, "step": 1, "display": "number" }),
"rev2_crop": (["center","top", "bottom", "left", "right"],),
"rev2_offset": ("INT", { "default": 0, "min": -2048, "max": 2048, "step": 1, "display": "number" }),
"crop_intpol": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"crop_res": ("INT", { "default": 224 , "min": 224, "max": 1792, "step": 224, "display": "number" }),
}
}
RETURN_TYPES = ("BASIC_PIPE",)
RETURN_NAMES = ("revision_settings",)
FUNCTION = "get_revmode"
CATEGORY="JPS Nodes/Settings"
def get_revmode(self,crop_res,crop_intpol,rev1_crop,rev1_offset,rev2_crop,rev2_offset,rev1_strength,rev2_strength,rev1_noiseaug,rev2_noiseaug,):
rev1strength = 0
rev1noiseaug = 0
rev2strength = 0
rev2noiseaug = 0
rev1strength = rev1_strength
rev1noiseaug = rev1_noiseaug
rev2strength = rev2_strength
rev2noiseaug = rev2_noiseaug
revision_settings = crop_res,crop_intpol,rev1_crop,rev1_offset,rev2_crop,rev2_offset,rev1strength,rev2strength,rev1noiseaug,rev2_noiseaug
return(revision_settings,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Revision_Settings_Pipe:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"revision_settings": ("BASIC_PIPE",),
}
}
RETURN_TYPES = ("INT",["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],["center","top", "bottom", "left", "right"],"INT",["center","top", "bottom", "left", "right"],"INT","FLOAT","FLOAT","FLOAT","FLOAT",)
RETURN_NAMES = ("crop_res", "crop_intpol", "rev1_crop", "rev1_offset", "rev2_crop", "rev2_offset", "rev1_strength", "rev2_strength", "rev1_noiseaug", "rev2_noiseaug",)
FUNCTION = "get_revmode"
CATEGORY="JPS Nodes/Pipes"
def get_revmode(self,revision_settings):
crop_res,crop_intpol,rev1_crop,rev1_offset,rev2_crop,rev2_offset,rev1strength,rev2strength,rev1noiseaug,rev2noiseaug = revision_settings
return(int(crop_res),crop_intpol,rev1_crop,int(rev1_offset),rev2_crop,int(rev2_offset),float(rev1strength),float(rev2strength),float(rev1noiseaug),float(rev2noiseaug),)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Sampler_Scheduler_Settings:
CATEGORY = 'JPS Nodes/Settings'
RETURN_TYPES = (comfy.samplers.KSampler.SAMPLERS,comfy.samplers.KSampler.SCHEDULERS,)
RETURN_NAMES = ("sampler_name","scheduler",)
FUNCTION = "get_samsched"
@classmethod
def INPUT_TYPES(cls):
return {"required": {"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),"scheduler": (comfy.samplers.KSampler.SCHEDULERS,)}}
def get_samsched(self, sampler_name, scheduler):
return (sampler_name, scheduler, )
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Image_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("img_out",)
FUNCTION = "get_image"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"img_1": ("IMAGE",),
"img_2": ("IMAGE",),
"img_3": ("IMAGE",),
"img_4": ("IMAGE",),
"img_5": ("IMAGE",),
}
}
def get_image(self,select,img_1,img_2=None,img_3=None,img_4=None,img_5=None,):
img_out = img_1
if (select == 2):
img_out = img_2
elif (select == 3):
img_out = img_3
elif (select == 4):
img_out = img_4
elif (select == 5):
img_out = img_5
return (img_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Conditioning_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("CONDITIONING",)
RETURN_NAMES = ("con_out",)
FUNCTION = "get_con"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"con_1": ("CONDITIONING",),
"con_2": ("CONDITIONING",),
"con_3": ("CONDITIONING",),
"con_4": ("CONDITIONING",),
"con_5": ("CONDITIONING",),
}
}
def get_con(self,select,con_1,con_2=None,con_3=None,con_4=None,con_5=None,):
con_out = con_1
if (select == 2):
con_out = con_2
elif (select == 3):
con_out = con_3
elif (select == 4):
con_out = con_4
elif (select == 5):
con_out = con_5
return (con_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Model_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("MODEL",)
RETURN_NAMES = ("model_out",)
FUNCTION = "get_model"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"model_1": ("MODEL",),
"model_2": ("MODEL",),
"model_3": ("MODEL",),
"model_4": ("MODEL",),
"model_5": ("MODEL",),
}
}
def get_model(self,select,model_1,model_2=None,model_3=None,model_4=None,model_5=None,):
model_out = model_1
if (select == 2):
model_out = model_2
elif (select == 3):
model_out = model_3
elif (select == 4):
model_out = model_4
elif (select == 5):
model_out = model_5
return (model_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class IPA_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("IPADAPTER",)
RETURN_NAMES = ("IPA_out",)
FUNCTION = "get_ipa"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"ipa_1": ("IPADAPTER",),
"ipa_2": ("IPADAPTER",),
"ipa_3": ("IPADAPTER",),
"ipa_4": ("IPADAPTER",),
"ipa_5": ("IPADAPTER",),
}
}
def get_ipa(self,select,ipa_1,ipa_2=None,ipa_3=None,ipa_4=None,ipa_5=None,):
ipa_out = ipa_1
if (select == 2):
ipa_out = ipa_2
elif (select == 3):
ipa_out = ipa_3
elif (select == 4):
ipa_out = ipa_4
elif (select == 5):
ipa_out = ipa_5
return (ipa_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Latent_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("LATENT",)
RETURN_NAMES = ("latent_out",)
FUNCTION = "get_latent"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"latent_1": ("LATENT",),
"latent_2": ("LATENT",),
"latent_3": ("LATENT",),
"latent_4": ("LATENT",),
"latent_5": ("LATENT",),
}
}
def get_latent(self,select,latent_1=None,latent_2=None,latent_3=None,latent_4=None,latent_5=None,):
latent_out = latent_1
if (select == 2):
latent_out = latent_2
elif (select == 3):
latent_out = latent_3
elif (select == 4):
latent_out = latent_4
elif (select == 5):
latent_out = latent_5
return (latent_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class VAE_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("VAE",)
RETURN_NAMES = ("vae_out",)
FUNCTION = "get_vae"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"vae_1": ("VAE",),
"vae_2": ("VAE",),
"vae_3": ("VAE",),
"vae_4": ("VAE",),
"vae_5": ("VAE",),
}
}
def get_vae(self,select,vae_1=None,vae_2=None,vae_3=None,vae_4=None,vae_5=None,):
vae_out = vae_1
if (select == 2):
vae_out = vae_2
elif (select == 3):
vae_out = vae_3
elif (select == 4):
vae_out = vae_4
elif (select == 5):
vae_out = vae_5
return (vae_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Integer_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("int_out",)
FUNCTION = "get_int"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"int_1": ("INT", {}),
"int_2": ("INT", {}),
"int_3": ("INT", {}),
"int_4": ("INT", {}),
"int_5": ("INT", {}),
}
}
def get_int(self,select,int_1=None,int_2=None,int_3=None,int_4=None,int_5=None,):
int_out = int_1
if (select == 2):
int_out = int_2
elif (select == 3):
int_out = int_3
elif (select == 4):
int_out = int_4
elif (select == 5):
int_out = int_5
return (int_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Mask_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("MASK",)
RETURN_NAMES = ("mask_out",)
FUNCTION = "get_mask"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"mask_1": ("MASK",),
"mask_2": ("MASK",),
"mask_3": ("MASK",),
"mask_4": ("MASK",),
"mask_5": ("MASK",),
}
}
def get_mask(self,select,mask_1=None,mask_2=None,mask_3=None,mask_4=None,mask_5=None,):
mask_out = None
if (select == 1):
mask_out = mask_1
if (select == 2):
mask_out = mask_2
elif (select == 3):
mask_out = mask_3
elif (select == 4):
mask_out = mask_4
elif (select == 5):
mask_out = mask_5
return (mask_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class ControlNet_Switch:
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = ("CONTROL_NET",)
RETURN_NAMES = ("ctrlnet_out",)
FUNCTION = "get_ctrlnet"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"select": ("INT", {}),
},
"optional": {
"ctrlnet_1": ("CONTROL_NET",),
"ctrlnet_2": ("CONTROL_NET",),
"ctrlnet_3": ("CONTROL_NET",),
"ctrlnet_4": ("CONTROL_NET",),
"ctrlnet_5": ("CONTROL_NET",),
}
}
def get_ctrlnet(self,select,ctrlnet_1=None,ctrlnet_2=None,ctrlnet_3=None,ctrlnet_4=None,ctrlnet_5=None,):
ctrlnet_out = ctrlnet_1
if (select == 2):
ctrlnet_out = ctrlnet_2
elif (select == 3):
ctrlnet_out = ctrlnet_3
elif (select == 4):
ctrlnet_out = ctrlnet_4
elif (select == 5):
ctrlnet_out = ctrlnet_5
return (ctrlnet_out,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Fundamentals_MultiPipe:
CATEGORY = 'JPS Nodes/Pipes'
RETURN_TYPES = ("VAE","MODEL","MODEL","CLIP","CLIP","CONDITIONING","CONDITIONING","CONDITIONING","CONDITIONING","INT",)
RETURN_NAMES = ("vae","model_base","model_refiner","clip_base","clip_refiner","pos_base","neg_base","pos_refiner","neg_refiner","seed",)
FUNCTION = "get_sdxlfund"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"vae": ("VAE",),
"model_base": ("MODEL",),
"model_refiner": ("MODEL",),
"clip_base": ("CLIP",),
"clip_refiner": ("CLIP",),
"pos_base": ("CONDITIONING",),
"neg_base": ("CONDITIONING",),
"pos_refiner": ("CONDITIONING",),
"neg_refiner": ("CONDITIONING",),
"seed": ("INT", {}),
}
}
def get_sdxlfund(self,vae=None,model_base=None,model_refiner=None,clip_base=None,clip_refiner=None,pos_base=None,neg_base=None,pos_refiner=None,neg_refiner=None,seed=None):
return (vae,model_base,model_refiner,clip_base,clip_refiner,pos_base,neg_base,pos_refiner,neg_refiner,seed,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Images_Masks_MultiPipe:
CATEGORY = 'JPS Nodes/Pipes'
RETURN_TYPES = ("IMAGE","MASK","IMAGE","IMAGE","MASK","MASK","IMAGE","IMAGE","MODEL",)
RETURN_NAMES = ("generation_img","generation_mask","ipa1_img","ipa2_img","ipa1_mask","ipa2_mask","revision1_img","revision2_img","inpaint_model",)
FUNCTION = "get_imagemask"
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"generation_img": ("IMAGE",),
"generation_mask": ("MASK",),
"ipa1_img": ("IMAGE",),
"ipa2_img": ("IMAGE",),
"ipa1_mask": ("MASK",),
"ipa2_mask": ("MASK",),
"revision1_img": ("IMAGE",),
"revision2_img": ("IMAGE",),
"inpaint_model": ("MODEL",),
}
}
def get_imagemask(self,generation_img=None,generation_mask=None,ipa1_img=None,ipa2_img=None,ipa1_mask=None,ipa2_mask=None,revision1_img=None,revision2_img=None,inpaint_model=None,):
return (generation_img,generation_mask,ipa1_img,ipa2_img,ipa1_mask,ipa2_mask,revision1_img,revision2_img,inpaint_model,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Disable_Enable_Switch:
match = ["Set to Disable","Set to Enable"]
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = (["disable","enable"],)
RETURN_NAMES = ("disable_enable",)
FUNCTION = "get_disenable"
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"select": ("INT", {"default": 1, "min": 1, "max": 9, "step": 1}),
"compare": ("INT", {"default": 1, "min": 1, "max": 9, "step": 1}),
"match": (s.match,),
}
}
def get_disenable(self,select,compare,match):
disable_enable = "disable"
if match == "Set to Enable" and (int(select) == int(compare)):
disable_enable = "enable"
elif match == "Set to Disable" and (int(select) == int(compare)):
disable_enable = "disable"
elif match == "Set to Enable" and (int(select) != int(compare)):
disable_enable = "disable"
elif match == "Set to Disable" and (int(select) != int(compare)):
disable_enable = "enable"
return (disable_enable, )
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Enable_Disable_Switch:
match = ["Set to Enable","Set to Disable"]
CATEGORY = 'JPS Nodes/Switches'
RETURN_TYPES = (["enable","disable"],)
RETURN_NAMES = ("enable_disable",)
FUNCTION = "get_endisable"
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"select": ("INT", {"default": 1, "min": 1, "max": 9, "step": 1}),
"compare": ("INT", {"default": 1, "min": 1, "max": 9, "step": 1}),
"match": (s.match,),
}
}
def get_endisable(self,select,compare,match):
enable_disable = "disable"
if match == "Set to Enable" and (int(select) == int(compare)):
enable_disable = "enable"
elif match == "Set to Disable" and (int(select) == int(compare)):
enable_disable = "disable"
elif match == "Set to Enable" and (int(select) != int(compare)):
enable_disable = "disable"
elif match == "Set to Disable" and (int(select) != int(compare)):
enable_disable = "enable"
return (enable_disable, )
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class IO_Lora_Loader:
def __init__(self):
self.loaded_lora = None
@classmethod
def INPUT_TYPES(s):
file_list = folder_paths.get_filename_list("loras")
file_list.insert(0, "None")
return {"required": { "model": ("MODEL",),
"clip": ("CLIP", ),
"switch": ([
"Off",
"On"],),
"lora_name": (file_list, ),
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.1}),
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.1}),
}}
RETURN_TYPES = ("MODEL", "CLIP")
FUNCTION = "load_lora"
CATEGORY = "JPS Nodes/IO"
def load_lora(self, model, clip, switch, lora_name, strength_model, strength_clip):
if strength_model == 0 and strength_clip == 0:
return (model, clip)
if switch == "Off" or lora_name == "None":
return (model, clip)
lora_path = folder_paths.get_full_path("loras", lora_name)
lora = None
if self.loaded_lora is not None:
if self.loaded_lora[0] == lora_path:
lora = self.loaded_lora[1]
else:
del self.loaded_lora
if lora is None:
lora = comfy.utils.load_torch_file(lora_path, safe_load=True)
self.loaded_lora = (lora_path, lora)
model_lora, clip_lora = comfy.sd.load_lora_for_models(model, clip, lora, strength_model, strength_clip)
return (model_lora, clip_lora)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Get_Image_Size:
def __init__(self) -> None:
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
}
}
RETURN_TYPES = ("INT", "INT",)
RETURN_NAMES = ("width", "height",)
CATEGORY = "JPS Nodes/Image"
FUNCTION = 'get_imagesize'
def get_imagesize(self, image):
samples = image.movedim(-1,1)
size_w = samples.shape[3]
size_h = samples.shape[2]
return (size_w, size_h, )
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class SDXL_Prompt_Styler:
def __init__(self):
pass
uni_neg = ["OFF","ON"]
@classmethod
def INPUT_TYPES(self):
current_directory = os.path.dirname(os.path.realpath(__file__))
self.json_data_artists, artists = load_styles_from_directory(os.path.join(current_directory, 'styles', 'artists'))
self.json_data_movies, movies = load_styles_from_directory(os.path.join(current_directory, 'styles', 'movies'))
self.json_data_styles, styles = load_styles_from_directory(os.path.join(current_directory, 'styles', 'main'))
return {
"required": {
"text_positive_g": ("STRING", {"default": "", "multiline": True, "dynamicPrompts": True}),
"text_positive_l": ("STRING", {"default": "", "multiline": True, "dynamicPrompts": True}),
"text_negative": ("STRING", {"default": "", "multiline": True, "dynamicPrompts": True}),
"artist": ((artists), ),
"movie": ((movies), ),
"style": ((styles), ),
"fooocus_enhance": (self.uni_neg,),
"fooocus_negative": (self.uni_neg,),
"universal_negative": (self.uni_neg,),
},
}
RETURN_TYPES = ('STRING','STRING','STRING','STRING',)
RETURN_NAMES = ('text_positive_g','text_positive_l','text_positive','text_negative',)
FUNCTION = 'sdxlpromptstyler'
CATEGORY = 'JPS Nodes/Style'
def sdxlpromptstyler(self, text_positive_g, text_positive_l, text_negative, artist, movie, style, fooocus_enhance, fooocus_negative, universal_negative):
# Process and combine prompts in templates
# The function replaces the positive prompt placeholder in the template,
# and combines the negative prompt with the template's negative prompt, if they exist.
text_pos_g_style = ""
text_pos_l_style = ""
text_pos_style = ""
text_neg_style = ""
text_pos_g_artist, text_pos_l_artist, text_neg_artist = read_sdxl_templates_replace_and_combine(self.json_data_artists, artist, text_positive_g, text_positive_l, text_negative)
if(text_positive_g == text_positive_l):
if(text_pos_l_artist != text_positive_l and text_pos_g_artist != text_positive_g):
text_positive_l = ""
text_pos_g_artist, text_pos_l_artist, text_neg_artist = read_sdxl_templates_replace_and_combine(self.json_data_artist, artist, text_positive_g, text_positive_l, text_negative)
elif(text_pos_g_artist != text_positive_g):
text_pos_l_artist = text_pos_g_artist
elif(text_pos_l_artist != text_positive_l):
text_pos_g_artist = text_pos_l_artist
text_pos_g_movie, text_pos_l_movie, text_neg_movie = read_sdxl_templates_replace_and_combine(self.json_data_movies, movie, text_pos_g_artist, text_pos_l_artist, text_negative)
if(text_pos_g_artist == text_pos_l_artist):
if(text_pos_l_movie != text_pos_l_artist and text_pos_g_movie != text_pos_g_artist):
text_pos_l_artist = ""
text_pos_g_movie, text_pos_l_movie, text_neg_movie = read_sdxl_templates_replace_and_combine(self.json_data_movie, movie, text_positive_g, text_positive_l, text_negative)
elif(text_pos_g_movie != text_pos_g_artist):
text_pos_l_movie = text_pos_g_movie
elif(text_pos_l_movie != text_pos_l_artist):
text_pos_g_movie = text_pos_l_movie
text_pos_g_style, text_pos_l_style, text_neg_style = read_sdxl_templates_replace_and_combine(self.json_data_styles, style, text_pos_g_movie, text_pos_l_movie, text_neg_movie)
if(text_pos_g_movie == text_pos_l_movie):
if(text_pos_l_movie != text_pos_l_style and text_pos_g_movie != text_pos_g_style):
text_pos_l_movie = ""
text_pos_g_style, text_pos_l_style, text_neg_style = read_sdxl_templates_replace_and_combine(self.json_data_styles, style, text_pos_g_movie, text_pos_l_movie, text_neg_movie)
elif(text_pos_g_movie != text_pos_g_style):
text_pos_l_style = text_pos_g_style
elif(text_pos_l_movie != text_pos_l_style):
text_pos_g_style = text_pos_l_style
if(text_pos_g_style != text_pos_l_style):
if(text_pos_l_style != ""):
text_pos_style = text_pos_g_style + ' . ' + text_pos_l_style
else:
text_pos_style = text_pos_g_style
else:
text_pos_style = text_pos_g_style
if(fooocus_enhance == "ON"):
if (text_neg_style != ''):
text_neg_style = text_neg_style + ', (worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art:1.4), (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name:1.2), (blur, blurry, grainy), morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur:1.3), (3D ,3D Game, 3D Game Scene, 3D Character:1.1), (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities:1.3)'
else:
text_neg_style = '(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art:1.4), (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name:1.2), (blur, blurry, grainy), morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur:1.3), (3D ,3D Game, 3D Game Scene, 3D Character:1.1), (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities:1.3)'
if(fooocus_negative == "ON"):
if (text_neg_style != ''):
text_neg_style = text_neg_style + ', deformed, bad anatomy, disfigured, poorly drawn face, mutated, extra limb, ugly, poorly drawn hands, missing limb, floating limbs, disconnected limbs, disconnected head, malformed hands, long neck, mutated hands and fingers, bad hands, missing fingers, cropped, worst quality, low quality, mutation, poorly drawn, huge calf, bad hands, fused hand, missing hand, disappearing arms, disappearing thigh, disappearing calf, disappearing legs, missing fingers, fused fingers, abnormal eye proportion, Abnormal hands, abnormal legs, abnormal feet, abnormal fingers, drawing, painting, crayon, sketch, graphite, impressionist, noisy, blurry, soft, deformed, ugly, anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch'
else:
text_neg_style = 'deformed, bad anatomy, disfigured, poorly drawn face, mutated, extra limb, ugly, poorly drawn hands, missing limb, floating limbs, disconnected limbs, disconnected head, malformed hands, long neck, mutated hands and fingers, bad hands, missing fingers, cropped, worst quality, low quality, mutation, poorly drawn, huge calf, bad hands, fused hand, missing hand, disappearing arms, disappearing thigh, disappearing calf, disappearing legs, missing fingers, fused fingers, abnormal eye proportion, Abnormal hands, abnormal legs, abnormal feet, abnormal fingers, drawing, painting, crayon, sketch, graphite, impressionist, noisy, blurry, soft, deformed, ugly, anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch'
if(universal_negative == "ON"):
if (text_neg_style != ''):
text_neg_style = text_neg_style + ', text, watermark, low-quality, signature, moire pattern, downsampling, aliasing, distorted, blurry, glossy, blur, jpeg artifacts, compression artifacts, poorly drawn, low-resolution, bad, distortion, twisted, excessive, exaggerated pose, exaggerated limbs, grainy, symmetrical, duplicate, error, pattern, beginner, pixelated, fake, hyper, glitch, overexposed, high-contrast, bad-contrast'
else:
text_neg_style = 'text, watermark, low-quality, signature, moire pattern, downsampling, aliasing, distorted, blurry, glossy, blur, jpeg artifacts, compression artifacts, poorly drawn, low-resolution, bad, distortion, twisted, excessive, exaggerated pose, exaggerated limbs, grainy, symmetrical, duplicate, error, pattern, beginner, pixelated, fake, hyper, glitch, overexposed, high-contrast, bad-contrast'
return text_pos_g_style, text_pos_l_style, text_pos_style, text_neg_style
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Crop_Image_Square:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"crop_position": (["center", "top", "bottom", "left", "right"],),
"offset_x": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"offset_y": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"zoom": ("FLOAT", { "default": 1, "min": 1, "max": 5, "step": 0.1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"target_rez": ("INT", { "default": 0 , "min": 0, "step": 8, "display": "number" }),
"sharpening": ("FLOAT", {"default": 0.0, "min": 0, "max": 1, "step": 0.05}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "crop_square"
CATEGORY = "JPS Nodes/Image"
def crop_square(self, image, crop_position, offset_x, offset_y, zoom, interpolation, target_rez,sharpening):
_, h, w, _ = image.shape
crop_size = min(h, w)
offset_x = int (offset_x * zoom)
offset_y = int (offset_y * zoom)
if "center" in crop_position:
x = round((w*zoom-crop_size) / 2)
y = round((h*zoom-crop_size) / 2)
if "top" in crop_position:
x = round((w*zoom-crop_size) / 2)
y = 0
if "bottom" in crop_position:
x = round((w*zoom-crop_size) / 2)
y = h*zoom-crop_size
if "left" in crop_position:
x = 0
y = round((h*zoom-crop_size) / 2)
if "right" in crop_position:
x = w*zoom-crop_size
y = round((h*zoom-crop_size) / 2)
x = int(x)
y = int(y)
if (x + offset_x >= 0 and x + crop_size + offset_x <= int(w*zoom)):
x = x + offset_x
elif (x + offset_x >= 0):
x = int(w*zoom) - crop_size
elif (x + crop_size + offset_x <= int(w*zoom)):
x = 0
if (y + offset_y >= 0 and y + crop_size + offset_y <= int(h*zoom)):
y = y + offset_y
elif (y + offset_y >= 0):
y = int(h*zoom) - crop_size
elif (y + crop_size + offset_y <= int(h*zoom)):
y = 0
x2 = x+crop_size
y2 = y+crop_size
zoomedimage = image[:, 0:h, 0:w, :]
zoomedimage = zoomedimage.permute([0,3,1,2])
zoomedimage = comfy.utils.lanczos(zoomedimage, int(w*zoom), int(h*zoom))
zoomedimage = zoomedimage.permute([0,2,3,1])
output = zoomedimage[:, y:y2, x:x2, :]
output = output.permute([0,3,1,2])
if target_rez != 0:
if interpolation == "lanczos":
output = comfy.utils.lanczos(output, target_rez, target_rez)
else:
output = F.interpolate(output, size=(target_rez, target_rez), mode=interpolation)
if sharpening > 0:
output = contrast_adaptive_sharpening(output, sharpening)
output = output.permute([0,2,3,1])
return(output, )
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Crop_Image_TargetSize:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"target_w": ("INT", { "default": 0 , "min": 0, "step": 8, "display": "number" }),
"target_h": ("INT", { "default": 0 , "min": 0, "step": 8, "display": "number" }),
"crop_position": (["center","top", "bottom", "left", "right"],),
"offset": ("INT", { "default": 0, "min": -2048, "max": 2048, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", {"default": 0.0, "min": 0, "max": 1, "step": 0.05}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "crop_targetsize"
CATEGORY = "JPS Nodes/Image"
def crop_targetsize(self, image, target_w, target_h, crop_position, offset, interpolation, sharpening):
_, current_h, current_w, _ = image.shape
current_ar = current_w / current_h
if target_w / current_ar >= target_h:
new_w = target_w
new_h = round(new_w / current_ar)
offset_h = offset
offset_w = 0
else:
new_h = target_h
new_w = round(new_h * current_ar)
offset_w = offset
offset_h = 0
# print("New Size")
# print(new_w)
# print(new_h)
resized_image = image.permute([0,3,1,2])
if interpolation == "lanczos":
resized_image = comfy.utils.lanczos(resized_image, new_w, new_h)
else:
resized_image = F.interpolate(resized_image, size=(new_h, new_w), mode=interpolation)
resized_image = resized_image.permute([0,2,3,1])
output_image = resized_image
if (crop_position == "left"):
newoffset_w = offset_w
elif (crop_position == "right"):
newoffset_w = new_w - target_w + offset_w
else:
newoffset_w = (new_w - target_w) // 2 + offset_w
if (crop_position == "top"):
newoffset_h = offset_h
elif (crop_position == "bottom"):
newoffset_h = new_h - target_h + offset_h
else:
newoffset_h = (new_h - target_h) // 2 + offset_h
if newoffset_w < 0:
newoffset_w = 0
elif newoffset_w + target_w > new_w:
newoffset_w = new_w - target_w
if newoffset_h < 0:
newoffset_h = 0
elif newoffset_h + target_h > new_h:
newoffset_h = new_h - target_h
x = newoffset_w
x2 = newoffset_w+target_w
y = newoffset_h
y2 = newoffset_h+target_h
# print("x: "+str(x))
# print("x2: "+str(x2))
# print("y: "+str(y))
# print("y2: "+str(y2))
if sharpening > 0:
output_image = contrast_adaptive_sharpening(output_image, sharpening)
output_image = output_image[:, y:y2, x:x2, :]
return(output_image, )
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Prepare_Image_Tiled_IPA:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"target_w": ("INT", { "default": 0 , "min": 0, "step": 8, "display": "number" }),
"target_h": ("INT", { "default": 0 , "min": 0, "step": 8, "display": "number" }),
"zoom": ("INT", {"default": 1.0, "min": 1, "max": 500, "step": 1}),
"offset_w": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"offset_h": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", {"default": 0.0, "min": 0, "max": 1, "step": 0.05}),
"tile_short": ("INT", {"default": 2.0, "min": 1, "max": 5, "step": 1}),
"prepare_type": ("INT", {"default": 1, "min": 1, "max": 9, "step": 1}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "crop_targetsize"
CATEGORY = "JPS Nodes/Image"
def crop_targetsize(self, image, target_w, target_h, zoom, offset_w, offset_h, interpolation, sharpening,tile_short,prepare_type):
_, input_h, input_w, _ = image.shape
tilelength = tile_short * 224
#Direct Source
if prepare_type == 9:
copyimage = image
#Source_AR + Source_Res
if prepare_type == 4:
target_w = input_w
target_h = input_h
#Source_AR + Tile_Res
if prepare_type == 5:
target_w = input_w
target_h = input_h
prepare_type = 2
#Tile_AR + Source_Res
if prepare_type == 6:
target_w = input_w
target_h = input_h
prepare_type = 3
#Square_AR + Target_Res
if prepare_type == 7:
target_ar = target_w / target_h
if target_ar >= 1:
target_w = target_h
else:
target_h = target_w
#Square_AR + Tile_Res
if prepare_type == 8:
target_w = tilelength
target_h = tilelength
#Target_AR + Tile_Res
if prepare_type == 2:
target_ar = target_w / target_h
if target_ar >= 1:
target_h = tilelength
target_w = round(tilelength * target_ar)
else:
target_w = tilelength
target_h = round(tilelength / target_ar)
#Tile_AR + Target_Res
if prepare_type == 3:
target_ar = target_w / target_h
if target_ar >= 1:
target_h = tilelength
if target_ar < 1.5:
target_w = tilelength
elif target_ar < 2:
target_w = round(tilelength * 1.5)
elif target_ar < 2.5:
target_w = round(tilelength * 2)
elif target_ar < 3:
target_w = round(tilelength * 2.5)
elif target_ar < 3.5:
target_w = round(tilelength * 3)
else:
target_w = round(tilelength * target_ar)
else:
target_w = tilelength
target_ar = target_h / target_w
if target_ar < 1.5:
target_h = tilelength
elif target_ar < 2:
target_h = round(tilelength * 1.5)
elif target_ar < 2.5:
target_h = round(tilelength * 2)
elif target_ar < 3:
target_h = round(tilelength * 2.5)
elif target_ar < 3.5:
target_h = round(tilelength * 3)
else:
target_h = round(tilelength * target_ar)
zoom = float(zoom / 100)
resize_needed_w = target_w / input_w
resize_needed_h = target_h / input_h
if resize_needed_w >= resize_needed_h:
min_zoom_factor = resize_needed_w
else:
min_zoom_factor = resize_needed_h
if zoom <= min_zoom_factor:
zoom_factor = min_zoom_factor
# elif zoom > min_zoom_factor and min_zoom_factor >=1:
# zoom_factor = zoom
# elif zoom > min_zoom_factor and min_zoom_factor < 1:
# zoom_factor = min_zoom_factor
else:
zoom_factor = zoom
zoomed_w = round(input_w * zoom_factor)
zoomed_h = round(input_h * zoom_factor)
resized_image = image.permute([0,3,1,2])
if interpolation == "lanczos":
resized_image = comfy.utils.lanczos(resized_image, zoomed_w, zoomed_h)
else:
resized_image = F.interpolate(resized_image, size=(zoomed_h, zoomed_w), mode=interpolation)
resized_image = resized_image.permute([0,2,3,1])
x0 = round((zoomed_w - target_w) / 2)
x1 = x0 + target_w
y0 = round((zoomed_h - target_h) / 2)
y1 = y0 + target_h
if x0 + offset_w + target_w < zoomed_w and offset_w > 0:
x0 = x0 + offset_w
x1 = x0 + target_w
elif x0 + offset_w + target_w >= zoomed_w and offset_w > 0:
x0 = zoomed_w - target_w
x1 = zoomed_w
elif x0 + offset_w > 0 and offset_w < 0:
x0 = x0 + offset_w
x1 = x0 + target_w
elif x0 + offset_w <= 0 and offset_w < 0:
x0 = 0
x1 = target_w
if y0 + offset_h + target_h < zoomed_h and offset_h > 0:
y0 = y0 + offset_h
y1 = y0 + target_h
elif y0 + offset_h + target_h >= zoomed_h and offset_h > 0:
y0 = zoomed_h - target_h
y1 = zoomed_h
elif y0 + offset_h > 0 and offset_h < 0:
y0 = y0 + offset_h
y1 = y0 + target_h
elif y0 + offset_h <= 0 and offset_h < 0:
y0 = 0
y1 = target_h
output_image = resized_image
# print("x0: "+str(x0))
# print("x1: "+str(x1))
# print("y0: "+str(y0))
# print("y1: "+str(y1))
if sharpening > 0:
output_image = contrast_adaptive_sharpening(output_image, sharpening)
output_image = output_image[:, y0:y1, x0:x1, :]
if prepare_type == 9:
output_image = copyimage
return(output_image,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Prepare_Image:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"target_w": ("INT", { "default": 1024 , "min": 0, "step": 8, "display": "number" }),
"target_h": ("INT", { "default": 1024 , "min": 0, "step": 8, "display": "number" }),
"crop_w_percent": ("INT", { "default": 100 , "min": 10, "max": 100, "step": 1, "display": "number" }),
"crop_h_percent": ("INT", { "default": 100 , "min": 10, "max": 100, "step": 1, "display": "number" }),
"offset_w": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"offset_h": ("INT", { "default": 0, "min": -4096, "max": 4096, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", {"default": 0.0, "min": 0, "max": 1, "step": 0.05}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "prepare_image"
CATEGORY = "JPS Nodes/Image"
def prepare_image(self, image, target_w, target_h, crop_w_percent, crop_h_percent, offset_w, offset_h, interpolation, sharpening, padding_left, padding_right, padding_top, padding_bottom):
_, input_h, input_w, _ = image.shape
resize_needed_w = target_w / input_w / crop_w_percent * 100
resize_needed_h = target_h / input_h / crop_h_percent * 100
if resize_needed_w >= resize_needed_h:
min_zoom_factor = resize_needed_w
else:
min_zoom_factor = resize_needed_h
zoom_factor = min_zoom_factor
zoomed_w = round(input_w * zoom_factor)
zoomed_h = round(input_h * zoom_factor)
resized_image = image.permute([0,3,1,2])
if interpolation == "lanczos":
resized_image = comfy.utils.lanczos(resized_image, zoomed_w, zoomed_h)
else:
resized_image = F.interpolate(resized_image, size=(zoomed_h, zoomed_w), mode=interpolation)
resized_image = resized_image.permute([0,2,3,1])
x0 = round((zoomed_w - target_w) / 2)
x1 = round(x0 + target_w)
y0 = round((zoomed_h - target_h) / 2)
y1 = round(y0 + target_h)
if x0 + offset_w + target_w < zoomed_w and offset_w > 0:
x0 = x0 + offset_w
x1 = x0 + target_w
elif x0 + offset_w + target_w >= zoomed_w and offset_w > 0:
x0 = zoomed_w - target_w
x1 = zoomed_w
elif x0 + offset_w > 0 and offset_w < 0:
x0 = x0 + offset_w
x1 = x0 + target_w
elif x0 + offset_w <= 0 and offset_w < 0:
x0 = 0
x1 = target_w
if y0 + offset_h + target_h < zoomed_h and offset_h > 0:
y0 = y0 + offset_h
y1 = y0 + target_h
elif y0 + offset_h + target_h >= zoomed_h and offset_h > 0:
y0 = zoomed_h - target_h
y1 = zoomed_h
elif y0 + offset_h > 0 and offset_h < 0:
y0 = y0 + offset_h
y1 = y0 + target_h
elif y0 + offset_h <= 0 and offset_h < 0:
y0 = 0
y1 = target_h
output_image = resized_image
if sharpening > 0:
output_image = contrast_adaptive_sharpening(output_image, sharpening)
output_image = output_image[:, y0:y1, x0:x1, :]
return(output_image,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Prepare_Image_Plus:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"target_w": ("INT", { "default": 1024 , "min": 0, "step": 8, "display": "number" }),
"target_h": ("INT", { "default": 1024 , "min": 0, "step": 8, "display": "number" }),
"offset_w": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"offset_h": ("INT", { "default": 0, "min": -99, "max": 99, "step": 1, "display": "number" }),
"crop_left": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_right": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_top": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"crop_bottom": ("INT", { "default": 0, "min": 0, "max": 90, "step": 1, "display": "number" }),
"padding_left": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_right": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_top": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"padding_bottom": ("INT", { "default": 0, "min": 0, "max": 500, "step": 1, "display": "number" }),
"interpolation": (["lanczos", "nearest", "bilinear", "bicubic", "area", "nearest-exact"],),
"sharpening": ("FLOAT", {"default": 0.0, "min": 0, "max": 1, "step": 0.05}),
"resize_type": (["Crop", "Stretch"],),
"flip": (["No", "X-Axis", "Y-Axis"],),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "prepare_image"
CATEGORY = "JPS Nodes/Image"
def prepare_image(self, image, target_w, target_h, offset_w, offset_h, crop_left, crop_right, crop_top, crop_bottom, padding_left, padding_right, padding_top, padding_bottom,interpolation, sharpening,resize_type,flip):
_, input_h, input_w, _ = image.shape
dim = ()
if flip == "X-Axis":
dim += (2,)
image = torch.flip(image, dim)
if flip == "Y-Axis":
dim += (2,)
image = torch.flip(image, dim)
if crop_left + crop_right > 90:
crop_left = 90 / (crop_left + crop_right) * crop_left
crop_right = 90 / (crop_left + crop_right) * crop_right
if crop_top + crop_bottom > 90:
crop_top = 90 / (crop_top + crop_bottom) * crop_top
crop_bottom = 90 / (crop_top + crop_bottom) * crop_bottom
left = int(input_w-(input_w * (100-crop_left) / 100))
right = int(input_w-(input_w * (100-crop_right) / 100))
top = int(input_h-(input_h * (100-crop_top) / 100))
bottom = int(input_h-(input_h * (100-crop_bottom) / 100))
image = image[:, 0+top:input_h-bottom, 0+left:input_w-right, :]
input_h = input_h - top - bottom
input_w = input_w - left - right
left = int(((input_w * (100+padding_left) / 100) - input_w))
right = int(((input_w * (100+padding_right) / 100) - input_w))
top = int(((input_h * (100+padding_top) / 100) - input_h))
bottom = int(((input_h * (100+padding_bottom) / 100) - input_h))
pil_image = Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
padded_image = Image.new("RGB", (pil_image.width + left + right, pil_image.height + top + bottom), color="black")
padded_image.paste(pil_image, (left, top))
image = torch.from_numpy(np.array(padded_image).astype(np.float32) / 255.0).unsqueeze(0)
input_h = input_h + top + bottom
input_w = input_w + left + right
if resize_type != "Stretch":
resize_needed_w = target_w / input_w
resize_needed_h = target_h / input_h
if resize_needed_w >= resize_needed_h:
min_zoom_factor = resize_needed_w
else:
min_zoom_factor = resize_needed_h
zoom_factor = min_zoom_factor
zoomed_w = round(input_w * zoom_factor)
zoomed_h = round(input_h * zoom_factor)
offset_w = int(zoomed_w / 100 * offset_w / 2)
offset_h = int(zoomed_h / 100 * offset_h / 2)
resized_image = image.permute([0,3,1,2])
if interpolation == "lanczos":
resized_image = comfy.utils.lanczos(resized_image, zoomed_w, zoomed_h)
else:
resized_image = F.interpolate(resized_image, size=(zoomed_h, zoomed_w), mode=interpolation)
resized_image = resized_image.permute([0,2,3,1])
x0 = round((zoomed_w - target_w) / 2)
x1 = round(x0 + target_w)
y0 = round((zoomed_h - target_h) / 2)
y1 = round(y0 + target_h)
if x0 + offset_w + target_w < zoomed_w and offset_w > 0:
x0 = x0 + offset_w
x1 = x0 + target_w
elif x0 + offset_w + target_w >= zoomed_w and offset_w > 0:
x0 = zoomed_w - target_w
x1 = zoomed_w
elif x0 + offset_w > 0 and offset_w < 0:
x0 = x0 + offset_w
x1 = x0 + target_w
elif x0 + offset_w <= 0 and offset_w < 0:
x0 = 0
x1 = target_w
if y0 + offset_h + target_h < zoomed_h and offset_h > 0:
y0 = y0 + offset_h
y1 = y0 + target_h
elif y0 + offset_h + target_h >= zoomed_h and offset_h > 0:
y0 = zoomed_h - target_h
y1 = zoomed_h
elif y0 + offset_h > 0 and offset_h < 0:
y0 = y0 + offset_h
y1 = y0 + target_h
elif y0 + offset_h <= 0 and offset_h < 0:
y0 = 0
y1 = target_h
output_image = resized_image
output_image = output_image[:, y0:y1, x0:x1, :]
else:
resized_image = image.permute([0,3,1,2])
if interpolation == "lanczos":
resized_image = comfy.utils.lanczos(resized_image, target_w, target_h)
else:
resized_image = F.interpolate(resized_image, size=(target_h, target_w), mode=interpolation)
resized_image = resized_image.permute([0,2,3,1])
output_image = resized_image
if sharpening > 0:
output_image = contrast_adaptive_sharpening(output_image, sharpening)
return(output_image,)
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class Save_Images_Plus:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
self.type = "output"
self.prefix_append = ""
self.compress_level = 4
@classmethod
def INPUT_TYPES(s):
return {"required":
{"images": ("IMAGE", ),
"filename_prefix": ("STRING", {"default": "ComfyUI"})},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
}
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("dummy_out",)
FUNCTION = "save_images_plus"
OUTPUT_NODE = True
CATEGORY = "JPS Nodes/IO"
def save_images_plus(self, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
filename_prefix += self.prefix_append
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0])
results = list()
for image in images:
i = 255. * image.cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
metadata = None
if not args.disable_metadata:
metadata = PngInfo()
if prompt is not None:
metadata.add_text("prompt", json.dumps(prompt))
if extra_pnginfo is not None:
for x in extra_pnginfo:
metadata.add_text(x, json.dumps(extra_pnginfo[x]))
file = f"{filename} {counter:03}.png"
img.save(os.path.join(full_output_folder, file), pnginfo=metadata, compress_level=self.compress_level)
results.append({
"filename": file,
"subfolder": subfolder,
"type": self.type
})
counter += 1
#return { "ui": { "images": results } }
return(int(1), )
#---------------------------------------------------------------------------------------------------------------------------------------------------#
class CLIPTextEncodeSDXL_Plus:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"width": ("INT", {"default": 1024.0, "min": 0, "max": 12288}),
"height": ("INT", {"default": 1024.0, "min": 0, "max": 12288}),
"res_factor": ("INT", {"default": 4, "min": 1, "max": 8}),
"text_pos": ("STRING", {"multiline": True, "default": "", "dynamicPrompts": True}),
"text_neg": ("STRING", {"multiline": True, "default": "", "dynamicPrompts": True}),
"clip": ("CLIP", ),
}}
RETURN_TYPES = ("CONDITIONING","CONDITIONING",)
RETURN_NAMES = ("cond_pos", "cond_neg",)
FUNCTION = "execute"
CATEGORY = "JPS Nodes/Conditioning"
def execute(self, clip, width, height, res_factor, text_pos, text_neg):
crop_w = 0
crop_h = 0
width = width*res_factor
height = height*res_factor
target_width = width
target_height = height
text_g_pos = text_l_pos = text_pos
text_g_neg = text_l_neg = text_neg
tokens_pos = clip.tokenize(text_g_pos)
tokens_pos["l"] = clip.tokenize(text_l_pos)["l"]
if len(tokens_pos["l"]) != len(tokens_pos["g"]):
empty_pos = clip.tokenize("")
while len(tokens_pos["l"]) < len(tokens_pos["g"]):
tokens_pos["l"] += empty_pos["l"]
while len(tokens_pos["l"]) > len(tokens_pos["g"]):
tokens_pos["g"] += empty_pos["g"]
cond_pos, pooled_pos = clip.encode_from_tokens(tokens_pos, return_pooled=True)
tokens_neg = clip.tokenize(text_g_neg)
tokens_neg["l"] = clip.tokenize(text_l_neg)["l"]
if len(tokens_neg["l"]) != len(tokens_neg["g"]):
empty_neg = clip.tokenize("")
while len(tokens_neg["l"]) < len(tokens_neg["g"]):
tokens_neg["l"] += empty_neg["l"]
while len(tokens_pos["l"]) > len(tokens_pos["g"]):
tokens_neg["g"] += empty_neg["g"]
cond_neg, pooled_neg = clip.encode_from_tokens(tokens_neg, return_pooled=True)
return ([[cond_pos, {"pooled_output": pooled_pos, "width": width, "height": height, "crop_w": crop_w, "crop_h": crop_h, "target_width": target_width, "target_height": target_height}]], [[cond_neg, {"pooled_output": pooled_neg, "width": width, "height": height, "crop_w": crop_w, "crop_h": crop_h, "target_width": target_width, "target_height": target_height}]])
#---------------------------------------------------------------------------------------------------------------------------------------------------#
NODE_CLASS_MAPPINGS = {
"Lora Loader (JPS)": IO_Lora_Loader,
"SDXL Resolutions (JPS)": SDXL_Resolutions,
"SDXL Basic Settings (JPS)": SDXL_Basic_Settings,
"SDXL Settings (JPS)": SDXL_Settings,
"Generation TXT IMG Settings (JPS)": Generation_TXT_IMG_Settings,
"Crop Image Settings (JPS)": CropImage_Settings,
"ImageToImage Settings (JPS)": ImageToImage_Settings,
"CtrlNet CannyEdge Settings (JPS)": CtrlNet_CannyEdge_Settings,
"CtrlNet ZoeDepth Settings (JPS)": CtrlNet_ZoeDepth_Settings,
"CtrlNet MiDaS Settings (JPS)": CtrlNet_MiDaS_Settings,
"CtrlNet OpenPose Settings (JPS)": CtrlNet_OpenPose_Settings,
"Revision Settings (JPS)": Revision_Settings,
"IP Adapter Settings (JPS)": IP_Adapter_Settings,
"IP Adapter Tiled Settings (JPS)": IP_Adapter_Tiled_Settings,
"InstantID Settings (JPS)": InstantID_Settings,
"Image Prepare Settings (JPS)": ImagePrepare_Settings,
"InstantID Source Prepare Settings (JPS)": InstantIDSourcePrepare_Settings,
"InstantID Pose Prepare Settings (JPS)": InstantIDPosePrepare_Settings,
"InstantID Mask Prepare Settings (JPS)": InstantIDMaskPrepare_Settings,
"Sampler Scheduler Settings (JPS)": Sampler_Scheduler_Settings,
"Integer Switch (JPS)": Integer_Switch,
"Image Switch (JPS)": Image_Switch,
"Latent Switch (JPS)": Latent_Switch,
"Conditioning Switch (JPS)": Conditioning_Switch,
"Model Switch (JPS)": Model_Switch,
"IPA Switch (JPS)": IPA_Switch,
"VAE Switch (JPS)": VAE_Switch,
"Mask Switch (JPS)": Mask_Switch,
"ControlNet Switch (JPS)": ControlNet_Switch,
"Disable Enable Switch (JPS)": Disable_Enable_Switch,
"Enable Disable Switch (JPS)": Enable_Disable_Switch,
"SDXL Basic Settings Pipe (JPS)": SDXL_Basic_Settings_Pipe,
"SDXL Settings Pipe (JPS)": SDXL_Settings_Pipe,
"Crop Image Pipe (JPS)": CropImage_Pipe,
"ImageToImage Pipe (JPS)": ImageToImage_Pipe,
"CtrlNet CannyEdge Pipe (JPS)": CtrlNet_CannyEdge_Pipe,
"CtrlNet ZoeDepth Pipe (JPS)": CtrlNet_ZoeDepth_Pipe,
"CtrlNet MiDaS Pipe (JPS)": CtrlNet_MiDaS_Pipe,
"CtrlNet OpenPose Pipe (JPS)": CtrlNet_OpenPose_Pipe,
"IP Adapter Settings Pipe (JPS)": IP_Adapter_Settings_Pipe,
"IP Adapter Tiled Settings Pipe (JPS)": IP_Adapter_Tiled_Settings_Pipe,
"InstantID Pipe (JPS)": InstantID_Pipe,
"Image Prepare Pipe (JPS)": ImagePrepare_Pipe,
"InstantID Source Prepare Pipe (JPS)": InstantIDSourcePrepare_Pipe,
"InstantID Pose Prepare Pipe (JPS)": InstantIDPosePrepare_Pipe,
"InstantID Mask Prepare Pipe (JPS)": InstantIDMaskPrepare_Pipe,
"Revision Settings Pipe (JPS)": Revision_Settings_Pipe,
"SDXL Fundamentals MultiPipe (JPS)": SDXL_Fundamentals_MultiPipe,
"Images Masks MultiPipe (JPS)": Images_Masks_MultiPipe,
"SDXL Recommended Resolution Calc (JPS)": SDXL_Recommended_Resolution_Calc,
"Resolution Multiply (JPS)": Math_Resolution_Multiply,
"Largest Int (JPS)": Math_Largest_Integer,
"Multiply Int Int (JPS)": Math_Multiply_INT_INT,
"Multiply Int Float (JPS)": Math_Multiply_INT_FLOAT,
"Multiply Float Float (JPS)": Math_Multiply_FLOAT_FLOAT,
"Substract Int Int (JPS)": Math_Substract_INT_INT,
"Text Concatenate (JPS)": Text_Concatenate,
"Get Date Time String (JPS)": Get_Date_Time_String,
"Get Image Size (JPS)": Get_Image_Size,
"Crop Image Square (JPS)": Crop_Image_Square,
"Crop Image TargetSize (JPS)": Crop_Image_TargetSize,
"Prepare Image (JPS)": Prepare_Image,
"Prepare Image Plus (JPS)": Prepare_Image_Plus,
"Prepare Image Tiled IPA (JPS)": Prepare_Image_Tiled_IPA,
"SDXL Prompt Styler (JPS)": SDXL_Prompt_Styler,
"SDXL Prompt Handling (JPS)": SDXL_Prompt_Handling,
"SDXL Prompt Handling Plus (JPS)": SDXL_Prompt_Handling_Plus,
"Text Prompt (JPS)": Text_Prompt,
"Text Prompt Combo (JPS)": Text_Prompt_Combo,
"Save Images Plus (JPS)": Save_Images_Plus,
"CLIPTextEncode SDXL Plus (JPS)": CLIPTextEncodeSDXL_Plus,
"Time Seed (JPS)": Time_Seed,
}