new mask editor
This commit is contained in:
@@ -3,6 +3,11 @@ from comfy.model_management import InterruptProcessingException
|
||||
import os, random
|
||||
import torch
|
||||
|
||||
import base64
|
||||
import io
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
from .image_filter_messaging import send_and_wait, Response, TimeoutResponse
|
||||
|
||||
HIDDEN = {
|
||||
@@ -111,6 +116,7 @@ class TextImageFilterWithExtras(PreviewImage):
|
||||
"extra2" : ("STRING", {"default":""}),
|
||||
"extra3" : ("STRING", {"default":""}),
|
||||
"textareaheight" : ("INT", {"default": 150, "min": 50, "max": 500, "tooltip": "Height of text area in pixels"}),
|
||||
"graph_id": ("STRING", {"default":""}),
|
||||
},
|
||||
"hidden": HIDDEN,
|
||||
}
|
||||
@@ -155,6 +161,7 @@ class MaskImageFilter(PreviewImage, LoadImage):
|
||||
"extra1" : ("STRING", {"default":""}),
|
||||
"extra2" : ("STRING", {"default":""}),
|
||||
"extra3" : ("STRING", {"default":""}),
|
||||
"graph_id": ("STRING", {"default":""}),
|
||||
},
|
||||
"hidden": HIDDEN,
|
||||
}
|
||||
@@ -181,6 +188,19 @@ class MaskImageFilter(PreviewImage, LoadImage):
|
||||
return ( *(self.load_image(os.path.join('clipspace', response.masked_image)+" [input]")), *response.get_extras([extra1, extra2, extra3]) )
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
elif (response.masked_data):
|
||||
data = response.masked_data.split(',',1)[-1]
|
||||
bytes_data = data.encode('utf-8')
|
||||
image_data = base64.decodebytes(bytes_data)
|
||||
data_io = io.BytesIO(image_data)
|
||||
img = Image.open(data_io)
|
||||
|
||||
mask = np.array(img.getchannel('A')).astype(np.float32) / 255.0
|
||||
mask = 1. - torch.from_numpy(mask)
|
||||
mask = mask.unsqueeze(0)
|
||||
|
||||
return ( image, mask, *response.get_extras([extra1, extra2, extra3]) )
|
||||
|
||||
|
||||
if if_no_mask == 'cancel':
|
||||
raise InterruptProcessingException()
|
||||
|
||||
@@ -11,11 +11,17 @@ WAITING_FOR_RESPONSE = "-9"
|
||||
SPECIALS = [REQUEST_RESHOW, CANCEL, WAITING_FOR_RESPONSE]
|
||||
|
||||
class Response:
|
||||
def __init__(self, selection:Optional[list[str]] = None, text:Optional[str] = None,
|
||||
masked_image:Optional[str] = None, extras:Optional[list[str]] = None):
|
||||
def __init__(
|
||||
self,
|
||||
selection:Optional[list[str]] = None,
|
||||
text:Optional[str] = None,
|
||||
masked_image:Optional[str] = None,
|
||||
masked_data:Optional[str] = None,
|
||||
extras:Optional[list[str]] = None):
|
||||
self.selection:list[int] = [int(x) for x in selection] if selection else []
|
||||
self.text:Optional[str] = text
|
||||
self.masked_image:Optional[str] = masked_image
|
||||
self.masked_data:Optional[str] = masked_data
|
||||
self.extras:Optional[list[str]] = extras
|
||||
|
||||
def get_extras(self,defaults:list[str]) -> list[str]:
|
||||
|
||||
+33
-5
@@ -5,6 +5,8 @@ export function new_editor() {
|
||||
}
|
||||
|
||||
function get_mask_editor_element() {
|
||||
const newer = document.getElementsByClassName('p-dialog-mask')
|
||||
if (newer.length==1) return newer[0]
|
||||
return new_editor() ? document.getElementById('maskEditor') : document.getElementById('maskCanvas')?.parentElement
|
||||
}
|
||||
|
||||
@@ -13,17 +15,30 @@ export function mask_editor_showing() {
|
||||
}
|
||||
|
||||
export function hide_mask_editor() {
|
||||
if (mask_editor_showing()) document.getElementById('maskEditor').style.display = 'none'
|
||||
if (mask_editor_showing() && document.getElementById('maskEditor')) document.getElementById('maskEditor').style.display = 'none'
|
||||
}
|
||||
|
||||
function get_mask_editor_cancel_button() {
|
||||
if (document.getElementById("maskEditor_topBarCancelButton")) return document.getElementById("maskEditor_topBarCancelButton")
|
||||
return get_mask_editor_element?.parentElement?.lastChild?.childNodes[2]
|
||||
var button = document.getElementById("maskEditor_topBarCancelButton")
|
||||
if (button) return button
|
||||
try {
|
||||
button = Array.from(get_mask_editor_element().getElementsByTagName('button')).find((b)=>(b.ariaLabel=='Cancel'))
|
||||
if (button) return button
|
||||
} catch {}
|
||||
|
||||
return get_mask_editor_element().parentElement.lastChild.childNodes[2]
|
||||
|
||||
}
|
||||
|
||||
function get_mask_editor_save_button() {
|
||||
if (document.getElementById("maskEditor_topBarSaveButton")) return document.getElementById("maskEditor_topBarSaveButton")
|
||||
return get_mask_editor_element?.parentElement?.lastChild?.childNodes[2]
|
||||
var button = document.getElementById("maskEditor_topBarSaveButton")
|
||||
if (button) return button
|
||||
try {
|
||||
button = Array.from(get_mask_editor_element().getElementsByTagName('button')).find((b)=>(b.ariaLabel=='Save'))
|
||||
if (button) return button
|
||||
} catch {}
|
||||
|
||||
return get_mask_editor_element?.parentElement?.lastChild?.childNodes[1]
|
||||
}
|
||||
|
||||
export function mask_editor_listen_for_cancel(callback) {
|
||||
@@ -40,4 +55,17 @@ export function press_maskeditor_save() {
|
||||
|
||||
export function press_maskeditor_cancel() {
|
||||
get_mask_editor_cancel_button()?.click()
|
||||
}
|
||||
|
||||
export function open_maskeditor(node) {
|
||||
if (ComfyApp.open_maskeditor) {
|
||||
ComfyApp.copyToClipspace(node)
|
||||
ComfyApp.clipspace_return_node = node
|
||||
ComfyApp.open_maskeditor()
|
||||
} else {
|
||||
const me_extension = app.extensions.find((e)=>(e.name=='Comfy.MaskEditor'))
|
||||
const me_command = me_extension.commands.find((c)=>(c.id=='Comfy.MaskEditor.OpenMaskEditor'))
|
||||
app.canvas.selected_nodes = [node,]
|
||||
me_command.function()
|
||||
}
|
||||
}
|
||||
+12
-5
@@ -1,7 +1,7 @@
|
||||
import { app, ComfyApp } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js"
|
||||
|
||||
import { mask_editor_listen_for_cancel, mask_editor_showing, hide_mask_editor, press_maskeditor_cancel, press_maskeditor_save, new_editor } from "./mask_utils.js";
|
||||
import { mask_editor_listen_for_cancel, mask_editor_showing, hide_mask_editor, press_maskeditor_cancel, press_maskeditor_save, new_editor, open_maskeditor } from "./mask_utils.js";
|
||||
import { Log } from "./log.js";
|
||||
import { create } from "./utils.js";
|
||||
import { FloatingWindow } from "./floating_window.js";
|
||||
@@ -351,13 +351,14 @@ class Popup extends HTMLElement {
|
||||
} else {
|
||||
this.state = State.MASK
|
||||
this.node.imgs = []
|
||||
this.node.images = []
|
||||
detail.urls.forEach((url, i)=>{
|
||||
this.node.imgs.push( new Image() );
|
||||
this.node.imgs[i].src = api.apiURL( `/view?filename=${encodeURIComponent(url.filename)}&type=${url.type}&subfolder=${url.subfolder}`)
|
||||
this.node.images.push( url )
|
||||
})
|
||||
ComfyApp.copyToClipspace(this.node)
|
||||
ComfyApp.clipspace_return_node = this.node
|
||||
ComfyApp.open_maskeditor()
|
||||
this.node.imageIndex = 0
|
||||
open_maskeditor(this.node)
|
||||
this.seen_editor = false
|
||||
}
|
||||
setTimeout(this.wait_while_mask_editing.bind(this), 200)
|
||||
@@ -373,7 +374,13 @@ class Popup extends HTMLElement {
|
||||
if (mask_editor_showing()) {
|
||||
setTimeout(this.wait_while_mask_editing.bind(this), 100)
|
||||
} else {
|
||||
this._send_response({masked_image:this.extract_filename(this.node.imgs[0].src)})
|
||||
const masked_image = this.extract_filename(this.node.imgs[0].src)
|
||||
if (masked_image) {
|
||||
this._send_response({masked_image:this.extract_filename(this.node.imgs[0].src)})
|
||||
} else {
|
||||
this._send_response({masked_data:this.node.imgs[0].src})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user