Add support for sending output image to loaded image.

Simplify workflow of img2img with new feature.

* ADDED: 'recv img' button to LoadImage, LoadImageMask
* ADDED: 'send to img' button to SaveImage
This commit is contained in:
Lt.Dr.Data 2023-03-21 12:44:31 +09:00
parent e85fcb822b
commit 1da4ea5898
4 changed files with 69 additions and 2 deletions

View File

@ -724,7 +724,9 @@ class SaveImage:
def INPUT_TYPES(s):
return {"required":
{"images": ("IMAGE", ),
"filename_prefix": ("STRING", {"default": "ComfyUI"})},
"filename_prefix": ("STRING", {"default": "ComfyUI"}),
"send to img": ("IMAGESEND", )
},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
}
@ -806,7 +808,9 @@ class LoadImage:
if not os.path.exists(s.input_dir):
os.makedirs(s.input_dir)
return {"required":
{"image": (sorted(os.listdir(s.input_dir)), )},
{"image": (sorted(os.listdir(s.input_dir)), ),
"recv img": (["disable", "enable"], )
},
}
CATEGORY = "image"
@ -840,6 +844,7 @@ class LoadImageMask:
def INPUT_TYPES(s):
return {"required":
{"image": (sorted(os.listdir(s.input_dir)), ),
"recv img": (["disable", "enable"], ),
"channel": (["alpha", "red", "green", "blue"], ),}
}

View File

@ -7,6 +7,8 @@ import execution
import uuid
import json
import glob
from shutil import copyfile
try:
import aiohttp
from aiohttp import web
@ -84,6 +86,17 @@ class PromptServer():
files = glob.glob(os.path.join(self.web_root, 'extensions/**/*.js'), recursive=True)
return web.json_response(list(map(lambda f: "/" + os.path.relpath(f, self.web_root).replace("\\", "/"), files)))
@routes.get("/image/output_to_input/{name}")
async def copy_output_to_input_image(request):
name = request.match_info["name"]
src_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "output", name)
dest_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "input", name)
copyfile(src_dir,dest_dir)
return web.Response(status=200)
@routes.post("/upload/image")
async def upload_image(request):
upload_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "input")

View File

@ -124,6 +124,11 @@ class ComfyApi extends EventTarget {
return await resp.json();
}
async sendOutputToInputImage(name) {
await fetch(`/image/output_to_input/${name}`, { cache: "no-store" });
}
/**
*
* @param {number} number The index at which to queue the prompt, passing -1 will insert the prompt at the front of the queue

View File

@ -1,3 +1,6 @@
import { api } from "./api.js";
import { app } from "../../scripts/app.js";
function getNumberDefaults(inputData, defaultStep) {
let defaultVal = inputData[1]["default"];
let { min, max, step } = inputData[1];
@ -126,6 +129,47 @@ export const ComfyWidgets = {
return { widget: node.addWidget("text", inputName, defaultVal, () => {}, {}) };
}
},
IMAGESEND(node, inputName) {
function showImage(node,uploadWidget,name) {
// Position the image somewhere sensible
if (!node.imageOffset) {
node.imageOffset = uploadWidget.last_y ? uploadWidget.last_y + 25 : 75;
}
const img = new Image();
img.onload = () => {
node.imgs = [img];
app.graph.setDirtyCanvas(true);
};
img.src = `/view?filename=${name}&type=input`;
}
async function callback() {
const imageWidget = node.widgets.find((w) => w.name === "image");
const copied = false;
for(let i in app.graph._nodes) {
var n = app.graph._nodes[i];
if(n.type == "LoadImage" || n.type == "LoadImageMask") {
const recvWidget = n.widgets.find((w) => w.name === "recv img");
if(recvWidget.value == "enable") {
// copy current node image to 'recv img' enabled node
if(!copied) {
api.sendOutputToInputImage(imageWidget.value);
}
const thatImageWidget = n.widgets.find((w) => w.value === "image");
await showImage(n,thatImageWidget,imageWidget.value);
}
}
}
}
return { widget: node.addWidget("button", inputName, "", () => { callback(); }, {}) };
},
IMAGEUPLOAD(node, inputName, inputData, app) {
const imageWidget = node.widgets.find((w) => w.name === "image");
let uploadWidget;