commit 1021a8863ddbeb78e8b5d82bd45ef577d8ee0238 Author: xChenNing <1915664627@qq.com> Date: Sat Jul 12 18:15:05 2025 +0800 First update diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..97a4712 --- /dev/null +++ b/README.MD @@ -0,0 +1,18 @@ +# ComfyUI Image Pin + +### 简介 + +ComfyUI Image Pin 是一个 ComfyUI 的自定义节点,允许您在 ComfyUI 工作流中“钉住”图像。这对于在处理图表的其他部分时保持参考图像可见非常有用。 + +### 安装 + +1. 导航到您的 ComfyUI 安装目录下的 `custom_nodes` 文件夹。 +2. 克隆此仓库: + ```bash + git clone https://github.com/CheNing233/ComfyUI_Image_Pin.git + ``` +3. 重启 ComfyUI。 + +### 使用方法 + +搜索 `ImagePin` 节点 \ No newline at end of file diff --git a/README_EN.MD b/README_EN.MD new file mode 100644 index 0000000..6f8cb95 --- /dev/null +++ b/README_EN.MD @@ -0,0 +1,18 @@ +# ComfyUI Image Pin + +### Introduction + +ComfyUI Image Pin is a custom node for ComfyUI that allows you to pin images within the ComfyUI workflow. This is useful for keeping reference images visible while you work on other parts of your graph. + +### Installation + +1. Navigate to the `custom_nodes` directory of your ComfyUI installation. +2. Clone this repository: + ```bash + git clone https://github.com/your-username/comfyui_image_pin.git + ``` +3. Restart ComfyUI. + +### Usage + +Search for the `ImagePin` node \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..6816bb7 --- /dev/null +++ b/__init__.py @@ -0,0 +1,13 @@ +from .image_pin import ImagePin + +WEB_DIRECTORY = "js" + +NODE_CLASS_MAPPINGS = { + "ImagePin": ImagePin +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "ImagePin": "Image PinNode (Embed image b64 to workflow)" +} + +__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] \ No newline at end of file diff --git a/__pycache__/__init__.cpython-311.pyc b/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..c6ccc80 Binary files /dev/null and b/__pycache__/__init__.cpython-311.pyc differ diff --git a/__pycache__/image_pin.cpython-311.pyc b/__pycache__/image_pin.cpython-311.pyc new file mode 100644 index 0000000..e802a40 Binary files /dev/null and b/__pycache__/image_pin.cpython-311.pyc differ diff --git a/image_pin.py b/image_pin.py new file mode 100644 index 0000000..016384d --- /dev/null +++ b/image_pin.py @@ -0,0 +1,37 @@ +import torch +import numpy as np +from PIL import Image,ImageOps +import base64 +from io import BytesIO +import folder_paths +import os + +class ImagePin: + @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) + ["#DATA"], {"image_upload": True}), + "image_data": ("STRING", {"multiline": False}), + }, + } + + CATEGORY = "utils" + + RETURN_TYPES = ("IMAGE", "MASK") + FUNCTION = "load_image" + + def load_image(self, image, image_data): + image_data = base64.b64decode(image_data.split(",")[1]) + i = Image.open(BytesIO(image_data)) + i = ImageOps.exif_transpose(i) + image = i.convert("RGB") + 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") + return (image, mask.unsqueeze(0)) diff --git a/js/image_pin.js b/js/image_pin.js new file mode 100644 index 0000000..a81625e --- /dev/null +++ b/js/image_pin.js @@ -0,0 +1,71 @@ +import { ComfyApp, app } from "../../scripts/app.js"; + +function load_image(str) { + let base64String = canvas.toDataURL('image/png'); + let img = new Image(); + img.src = base64String; +} + +app.registerExtension({ + name: "Comfy.ImagePin", + nodeCreated(node, app) { + if(node.comfyClass === "ImagePin") { + let w = node.widgets.find(obj => obj.name === 'image_data'); + w.hidden = true; + + Object.defineProperty(w, 'value', { + set(v) { + if(v != '[IMAGE DATA]') + w._value = v; + }, + get() { + const stackTrace = new Error().stack; + if(!stackTrace.includes('draw') && !stackTrace.includes('graphToPrompt') && stackTrace.includes('app.js')) { + return "[IMAGE DATA]"; + } + else { + return w._value; + } + } + }); + + let set_img_act = (v) => { + node._img = v; + var canvas = document.createElement('canvas'); + canvas.width = v[0].width; + canvas.height = v[0].height; + + var context = canvas.getContext('2d'); + context.drawImage(v[0], 0, 0, v[0].width, v[0].height); + + var base64Image = canvas.toDataURL('image/png'); + w.value = base64Image; + }; + + Object.defineProperty(node, 'imgs', { + set(v) { + if (v && !v[0].complete) { + let orig_onload = v[0].onload; + v[0].onload = function(v2) { + if(orig_onload) + orig_onload(); + set_img_act(v); + }; + } + else { + set_img_act(v); + } + }, + get() { + if(this._img == undefined && w.value != '') { + this._img = [new Image()]; + if(w.value && w.value != '[IMAGE DATA]') + this._img[0].src = w.value; + } + + return this._img; + } + }); + } + } +}) \ No newline at end of file