change all the things
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
class ConstrainImage:
|
||||
"""
|
||||
A node that constrains an image to a maximum and minimum size while maintaining aspect ratio.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"max_width": ("INT", {"default": 1024, "min": 0}),
|
||||
"max_height": ("INT", {"default": 1024, "min": 0}),
|
||||
"min_width": ("INT", {"default": 0, "min": 0}),
|
||||
"min_height": ("INT", {"default": 0, "min": 0}),
|
||||
"crop_if_required": (["yes", "no"], {"default": "no"}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "constrain_image"
|
||||
CATEGORY = "image"
|
||||
OUTPUT_IS_LIST = (True,)
|
||||
|
||||
def constrain_image(self, images, max_width, max_height, min_width, min_height, crop_if_required):
|
||||
crop_if_required = crop_if_required == "yes"
|
||||
results = []
|
||||
for image in images:
|
||||
i = 255. * image.cpu().numpy()
|
||||
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8)).convert("RGB")
|
||||
|
||||
current_width, current_height = img.size
|
||||
aspect_ratio = current_width / current_height
|
||||
|
||||
constrained_width = max(min(current_width, min_width), max_width)
|
||||
constrained_height = max(min(current_height, min_height), max_height)
|
||||
|
||||
if constrained_width / constrained_height > aspect_ratio:
|
||||
constrained_width = max(int(constrained_height * aspect_ratio), min_width)
|
||||
if crop_if_required:
|
||||
constrained_height = int(current_height / (current_width / constrained_width))
|
||||
else:
|
||||
constrained_height = max(int(constrained_width / aspect_ratio), min_height)
|
||||
if crop_if_required:
|
||||
constrained_width = int(current_width / (current_height / constrained_height))
|
||||
|
||||
resized_image = img.resize((constrained_width, constrained_height), Image.ANTIALIAS)
|
||||
|
||||
if crop_if_required and (constrained_width > max_width or constrained_height > max_height):
|
||||
left = max((constrained_width - max_width) // 2, 0)
|
||||
top = max((constrained_height - max_height) // 2, 0)
|
||||
right = min(constrained_width, max_width) + left
|
||||
bottom = min(constrained_height, max_height) + top
|
||||
resized_image = resized_image.crop((left, top, right, bottom))
|
||||
|
||||
resized_image = np.array(resized_image).astype(np.float32) / 255.0
|
||||
resized_image = torch.from_numpy(resized_image)[None,]
|
||||
results.append(resized_image)
|
||||
|
||||
return (results,)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ConstrainImage|pysssss": ConstrainImage,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ConstrainImage|pysssss": "Constrain Image 🐍",
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
class ShowText:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"text": ("STRING", {"forceInput": True}),
|
||||
}}
|
||||
|
||||
INPUT_IS_LIST = True
|
||||
RETURN_TYPES = ("STRING",)
|
||||
FUNCTION = "notify"
|
||||
OUTPUT_NODE = True
|
||||
OUTPUT_IS_LIST = (True,)
|
||||
|
||||
CATEGORY = "utils"
|
||||
|
||||
def notify(self, text):
|
||||
return {"ui": {"text": text}, "result": (text,)}
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ShowText|pysssss": ShowText,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ShowText|pysssss": "Show Text 🐍",
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import re
|
||||
|
||||
class StringFunction:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"action": (["append", "replace"], {}),
|
||||
"tidy_tags": (["yes", "no"], {}),
|
||||
"text_a": ("STRING", {"multiline": True}),
|
||||
"text_b": ("STRING", {"multiline": True}),
|
||||
},
|
||||
"optional": {
|
||||
"text_c": ("STRING", {"multiline": True})
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
FUNCTION = "exec"
|
||||
CATEGORY = "utils"
|
||||
|
||||
def exec(self, action, tidy_tags, text_a, text_b, text_c=""):
|
||||
tidy_tags = tidy_tags == "yes"
|
||||
out = ""
|
||||
if action == "append":
|
||||
out = (", " if tidy_tags else "").join(filter(None, [text_a, text_b, text_c]))
|
||||
else:
|
||||
if text_c is None:
|
||||
text_c = ""
|
||||
if text_b.startswith("/") and text_b.endswith("/"):
|
||||
regex = text_b[1:-1]
|
||||
out = re.sub(regex, text_c, text_a)
|
||||
else:
|
||||
out = text_a.replace(text_b, text_c)
|
||||
if tidy_tags:
|
||||
out = out.replace(" ", " ").replace(" ,", ",").replace(",,", ",").replace(",,", ",")
|
||||
return (out, )
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"StringFunction|pysssss": StringFunction,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"StringFunction|pysssss": "String Function 🐍",
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
from server import PromptServer
|
||||
from aiohttp import web
|
||||
import os
|
||||
import inspect
|
||||
import json
|
||||
|
||||
root_directory = os.path.dirname(inspect.getfile(PromptServer))
|
||||
workflows_directory = os.path.join(root_directory, "pysssss-workflows")
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {}
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/pysssss/workflows")
|
||||
async def get_workflows(request):
|
||||
files = []
|
||||
for dirpath, directories, file in os.walk(workflows_directory):
|
||||
for file in file:
|
||||
if (file.endswith(".json")):
|
||||
files.append(os.path.relpath(os.path.join(
|
||||
dirpath, file), workflows_directory))
|
||||
return web.json_response(list(map(lambda f: os.path.splitext(f)[0].replace("\\", "/"), files)))
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/pysssss/workflows/{name:.+}")
|
||||
async def get_workflow(request):
|
||||
file = os.path.abspath(os.path.join(
|
||||
workflows_directory, request.match_info["name"] + ".json"))
|
||||
if os.path.commonpath([file, workflows_directory]) != workflows_directory:
|
||||
return web.Response(status=403)
|
||||
|
||||
return web.FileResponse(file)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/pysssss/workflows")
|
||||
async def save_workflow(request):
|
||||
json_data = await request.json()
|
||||
file = os.path.abspath(os.path.join(
|
||||
workflows_directory, json_data["name"] + ".json"))
|
||||
if os.path.commonpath([file, workflows_directory]) != workflows_directory:
|
||||
return web.Response(status=403)
|
||||
|
||||
if os.path.exists(file) and ("overwrite" not in json_data or json_data["overwrite"] == False):
|
||||
return web.Response(status=409)
|
||||
|
||||
sub_path = os.path.dirname(file)
|
||||
if not os.path.exists(sub_path):
|
||||
os.makedirs(sub_path)
|
||||
|
||||
with open(file, "w") as f:
|
||||
f.write(json.dumps(json_data["workflow"]))
|
||||
|
||||
return web.Response(status=201)
|
||||
Reference in New Issue
Block a user