Merge branch 'main' into lightbox-image-stuff
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
class ConstrainImageforVideo:
|
||||
"""
|
||||
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",)
|
||||
RETURN_NAMES = ("IMAGE",)
|
||||
FUNCTION = "constrain_image_for_video"
|
||||
CATEGORY = "image"
|
||||
|
||||
def constrain_image_for_video(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.LANCZOS)
|
||||
|
||||
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)
|
||||
all_images = torch.cat(results, dim=0)
|
||||
|
||||
return (all_images, all_images.size(0),)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ConstrainImageforVideo|pysssss": ConstrainImageforVideo,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ConstrainImageforVideo|pysssss": "Constrain Image for Video 🐍",
|
||||
}
|
||||
@@ -27,10 +27,11 @@ app.registerExtension({
|
||||
left: 0;
|
||||
top: 0;
|
||||
transform: translate(-100%, 0);
|
||||
width: 256px;
|
||||
height: 256px;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
width: 384px;
|
||||
height: 384px;
|
||||
background-size: contain;
|
||||
background-position: top right;
|
||||
background-repeat: no-repeat;
|
||||
filter: brightness(65%);
|
||||
}
|
||||
`,
|
||||
|
||||
+1
-1
@@ -410,7 +410,7 @@ app.registerExtension({
|
||||
api.addEventListener("executed", ({ detail }) => {
|
||||
if (visible && detail?.output?.images) {
|
||||
for (const src of detail.output.images) {
|
||||
const href = `/view?filename=${encodeURIComponent(src.filename)}&type=${
|
||||
const href = `./view?filename=${encodeURIComponent(src.filename)}&type=${
|
||||
src.type
|
||||
}&subfolder=${encodeURIComponent(src.subfolder)}&t=${+new Date()}`;
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ const ext = {
|
||||
if (!images || !images.length) return;
|
||||
const format = app.getPreviewFormatParam();
|
||||
const src = [
|
||||
`/view?filename=${encodeURIComponent(images[0].filename)}`,
|
||||
`./view?filename=${encodeURIComponent(images[0].filename)}`,
|
||||
`type=${images[0].type}`,
|
||||
`subfolder=${encodeURIComponent(images[0].subfolder)}`,
|
||||
`t=${+new Date()}${format}`,].join('&');
|
||||
|
||||
@@ -81,6 +81,9 @@ async function saveWorkflow(name, workflow, overwrite) {
|
||||
class PysssssWorkflows {
|
||||
async load() {
|
||||
this.workflows = await getWorkflows();
|
||||
if(this.workflows.length) {
|
||||
this.workflows.sort();
|
||||
}
|
||||
this.loadMenu.style.display = this.workflows.length ? "flex" : "none";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user