Merge branch 'main' into dev/uv-tools

This commit is contained in:
melMass
2024-01-17 21:19:16 +01:00
4 changed files with 99 additions and 36 deletions
+41 -29
View File
@@ -436,8 +436,11 @@ class MaskToImage:
return (pil2tensor(images),)
from typing import Optional
class ColoredImage:
"""Constant color image of given size"""
"""Constant color image of given size."""
def __init__(self) -> None:
pass
@@ -565,43 +568,52 @@ class ColoredImage:
return img.crop((left, top, right, bottom))
def render_img(
self, color, width, height, foreground_image=None, foreground_mask=None
self,
color,
width,
height,
foreground_image: Optional[torch.Tensor] = None,
foreground_mask: Optional[torch.Tensor] = None,
):
image = Image.new("RGBA", (width, height), color=color)
output = []
if foreground_image is not None:
if foreground_mask is None:
fg_images = tensor2pil(foreground_image)
for img in fg_images:
if image.size != img.size:
raise ValueError(
f"Dimension mismatch: image {image.size}, img {img.size}"
)
fg_images = tensor2pil(foreground_image)
fg_masks = [None] * len(
fg_images
) # Default to None for each foreground image
if img.mode != "RGBA":
raise ValueError(
f"Foreground image must be in 'RGBA' mode when no mask is provided, got {img.mode}"
)
if foreground_mask is not None:
if foreground_image.size()[0] != foreground_mask.size()[0]:
raise ValueError(
"Foreground image and mask must have same batch size"
)
fg_masks = tensor2pil(foreground_mask)
for fg_image, fg_mask in zip(fg_images, fg_masks):
# Resize and crop if dimensions mismatch
if fg_image.size != image.size:
fg_image = self.resize_and_crop(fg_image, image.size)
if fg_mask:
fg_mask = self.resize_and_crop(fg_mask, image.size)
if fg_mask:
output.append(
Image.alpha_composite(image, img).convert("RGB")
Image.composite(
fg_image.convert("RGBA"),
image,
fg_mask,
).convert("RGB")
)
else:
if fg_image.mode != "RGBA":
raise ValueError(
"Foreground image must be in 'RGBA' mode when no mask is provided, got {fg_image.mode}"
)
output.append(
Image.alpha_composite(image, fg_image).convert("RGB")
)
elif foreground_image.size[0] != foreground_mask.size[0]:
raise ValueError(
"Foreground image and mask must have same batch size"
)
else:
fg_images = tensor2pil(foreground_image)
fg_masks = tensor2pil(foreground_mask)
output.extend(
Image.composite(
fg_image.convert("RGBA"),
image,
fg_mask,
).convert("RGB")
for fg_image, fg_mask in zip(fg_images, fg_masks)
)
elif foreground_mask is not None:
log.warn("Mask ignored because no foreground image is given")
+33 -1
View File
@@ -20,6 +20,38 @@ export function makeUUID() {
return uuid
}
//- local storage manager
export class LocalStorageManager {
constructor(namespace) {
this.namespace = namespace;
}
_namespacedKey(key) {
return `${this.namespace}:${key}`;
}
set(key, value) {
const serializedValue = JSON.stringify(value);
localStorage.setItem(this._namespacedKey(key), serializedValue);
}
get(key, default_val = null) {
const value = localStorage.getItem(this._namespacedKey(key));
return value ? JSON.parse(value) : default_val;
}
remove(key) {
localStorage.removeItem(this._namespacedKey(key));
}
clear() {
Object.keys(localStorage)
.filter(k => k.startsWith(this.namespace + ':'))
.forEach(k => localStorage.removeItem(k));
}
}
// - log utilities
function createLogger(emoji, color, consoleMethod = 'log') {
@@ -378,7 +410,7 @@ function getBrightness(rgbObj) {
(parseInt(rgbObj[0]) * 299 +
parseInt(rgbObj[1]) * 587 +
parseInt(rgbObj[2]) * 114) /
1000
1000
)
}
+24 -5
View File
@@ -11,7 +11,7 @@
import { api } from '../../scripts/api.js'
import { app } from '../../scripts/app.js'
import { LocalStorageManager } from "./comfy_shared.js"
const styles = {
lighbox: {
position: 'fixed',
@@ -53,11 +53,31 @@ let currentImageIndex = 0
const imageUrls = []
let image_menu = null
let activated = true
const storage = new LocalStorageManager('mtb');
let activated = storage.get("image_feed", true)
app.registerExtension({
name: 'mtb.ImageFeed',
setup: () => {
app.ui.settings.addSetting({
id: 'mtb.imageFeed.enabled',
name: '[⚡mtb] Enable image feed',
type: 'boolean',
defaultValue: true,
attrs: {
style: {
fontFamily: 'monospace',
},
},
async onChange(value) {
storage.set("image_feed", value)
activated = value
},
})
},
init: async () => {
if (!activated) { return }
const pythongossFeed = app.extensions.find(
(e) => e.name == 'pysssss.ImageFeed'
)
@@ -230,9 +250,8 @@ app.registerExtension({
objectFit: 'cover',
})
img.src = `/view?filename=${encodeURIComponent(src.filename)}&type=${
src.type
}&subfolder=${encodeURIComponent(src.subfolder)}`
img.src = `/view?filename=${encodeURIComponent(src.filename)}&type=${src.type
}&subfolder=${encodeURIComponent(src.subfolder)}`
imageUrls.push(img.src)
+1 -1
View File
@@ -582,7 +582,7 @@ const mtb_widgets = {
setup: () => {
app.ui.settings.addSetting({
id: 'mtb.Debug.enabled',
name: '[mtb] Enable Debug (py and js)',
name: '[⚡mtb] Enable Debug (py and js)',
type: 'boolean',
defaultValue: false,