diff --git a/README.md b/README.md index 75cee44..dccd874 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# πŸ”— Comfyui : Bjornulf_custom_nodes v0.12 πŸ”— +# πŸ”— Comfyui : Bjornulf_custom_nodes v0.13 πŸ”— # Dependencies @@ -21,6 +21,7 @@ - **v0.10**: Add a new node : Loop (All Lines from input) - Iterate over all lines from an input text. - **v0.11**: Add a new node : Text with random Seed - Generate a random seed, along with text. - **v0.12**: Combine images : Add option to move vertically and horizontally. (from -50% to 150%) +- **v0.13**: Add a new node: Load image with transparency (alpha) - Load an image with transparency. # πŸ“ Nodes descriptions @@ -176,6 +177,7 @@ But you can sometimes also want a black and white image... Combine two images into a single image : a background and one (or several) transparent overlay. (allow to have a video there, just send all the frames and recombine them after.) Update 0.11 : Add option to move vertically and horizontally. (from -50% to 150%) ❗ Warning : For now, `background` is a static image. (I will allow video there later too.) +⚠️ Warning : If you want to directly load the image with transparency, use my node `πŸ–Ό Load Image with Transparency β–’` instead of the `Load Image` node. ## 25 - πŸŸ©βžœβ–’ Green Screen to Transparency ![Greenscreen to Transparency](screenshots/greeenscreen_to_transparency.png) @@ -224,4 +226,11 @@ Here is an example of the similarities that you want to avoid with SDXL with dif FLUX : Here is an example of 4 images without Random Seed node on the left, and on the right 4 images with Random Seed node : -![Text with random Seed 5](screenshots/result_random_seed.png) \ No newline at end of file +![Text with random Seed 5](screenshots/result_random_seed.png) + +## 29 - πŸ–Ό Load Image with Transparency β–’ +![Load image Alpha](screenshots/load_image_alpha.png) + +**Description:** +Load an image with transparency. +The default `Load Image` node will not load the transparency. \ No newline at end of file diff --git a/__init__.py b/__init__.py index 5a93e3d..bb1f55f 100644 --- a/__init__.py +++ b/__init__.py @@ -33,6 +33,7 @@ from .green_to_transparency import GreenScreenToTransparency from .random_line_from_input import RandomLineFromInput from .loop_lines import LoopAllLines from .random_seed_with_text import TextToStringAndSeed +from .load_image_alpha import LoadImageWithTransparency # from .check_black_image import CheckBlackImage # from .clear_vram import ClearVRAM @@ -41,6 +42,7 @@ from .random_seed_with_text import TextToStringAndSeed NODE_CLASS_MAPPINGS = { # "Bjornulf_CustomStringType": CustomStringType, "Bjornulf_ollamaLoader": ollamaLoader, + "Bjornulf_LoadImageWithTransparency": LoadImageWithTransparency, "Bjornulf_LoopAllLines": LoopAllLines, "Bjornulf_TextToStringAndSeed": TextToStringAndSeed, "Bjornulf_GreenScreenToTransparency": GreenScreenToTransparency, @@ -82,6 +84,7 @@ NODE_CLASS_MAPPINGS = { NODE_DISPLAY_NAME_MAPPINGS = { # "Bjornulf_CustomStringType": "!!! CUSTOM STRING TYPE !!!", "Bjornulf_ollamaLoader": "πŸ¦™ Ollama (Description)", + "Bjornulf_LoadImageWithTransparency": "πŸ–Ό Load Image with Transparency β–’", "Bjornulf_GreenScreenToTransparency": "πŸŸ©βžœβ–’ Green Screen to Transparency", # "Bjornulf_CheckBlackImage": "πŸ”² Check Black Image (Empty mask)", "Bjornulf_SaveBjornulfLobeChat": "πŸ–ΌπŸ’¬ Save image for Bjornulf LobeChat", diff --git a/load_image_alpha.py b/load_image_alpha.py new file mode 100644 index 0000000..b63bbf6 --- /dev/null +++ b/load_image_alpha.py @@ -0,0 +1,80 @@ +import os +import hashlib +import numpy as np +from PIL import Image, ImageOps, ImageSequence +import torch +import folder_paths +import node_helpers + +class LoadImageWithTransparency: + @classmethod + def INPUT_TYPES(s): + input_dir = folder_paths.get_input_directory() + files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f))] + return {"required": + {"image": (sorted(files), {"image_upload": True})}, + } + + CATEGORY = "image" + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "load_image_alpha" + + def load_image_alpha(self, image): + image_path = folder_paths.get_annotated_filepath(image) + + img = node_helpers.pillow(Image.open, image_path) + + output_images = [] + output_masks = [] + w, h = None, None + + excluded_formats = ['MPO'] + + for i in ImageSequence.Iterator(img): + i = node_helpers.pillow(ImageOps.exif_transpose, i) + + if i.mode == 'I': + i = i.point(lambda i: i * (1 / 255)) + image = i.convert("RGBA") + + if len(output_images) == 0: + w = image.size[0] + h = image.size[1] + + if image.size[0] != w or image.size[1] != h: + continue + + image = np.array(image).astype(np.float32) / 255.0 + image = torch.from_numpy(image)[None,] + if 'A' in i.getbands(): + mask = np.array(i.getchannel('A')).astype(np.float32) / 255.0 + mask = 1. - torch.from_numpy(mask) + else: + mask = torch.zeros((64,64), dtype=torch.float32, device="cpu") + output_images.append(image) + output_masks.append(mask.unsqueeze(0)) + + if len(output_images) > 1 and img.format not in excluded_formats: + output_image = torch.cat(output_images, dim=0) + output_mask = torch.cat(output_masks, dim=0) + else: + output_image = output_images[0] + output_mask = output_masks[0] + + return (output_image, output_mask) + + @classmethod + def IS_CHANGED(s, image): + image_path = folder_paths.get_annotated_filepath(image) + m = hashlib.sha256() + with open(image_path, 'rb') as f: + m.update(f.read()) + return m.digest().hex() + + @classmethod + def VALIDATE_INPUTS(s, image): + if not folder_paths.exists_annotated_filepath(image): + return "Invalid image file: {}".format(image) + + return True diff --git a/screenshots/load_image_alpha.png b/screenshots/load_image_alpha.png new file mode 100644 index 0000000..cfe40f6 Binary files /dev/null and b/screenshots/load_image_alpha.png differ