Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed61ca761a | ||
|
|
95ca17d816 | ||
|
|
db6c721a8f | ||
|
|
b5c68751aa | ||
|
|
7780bfd671 | ||
|
|
a56970693a | ||
|
|
c8b24fe84b | ||
|
|
798aabf333 | ||
|
|
d38a7aa558 | ||
|
|
0bdf1e47a6 | ||
|
|
a44016e57c | ||
|
|
35a9351e53 | ||
|
|
c1b2112bb8 |
@@ -1,4 +1,5 @@
|
||||
##
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -61,7 +62,7 @@ pip3 install -r requirements.txt
|
||||
|
||||
|
||||
|
||||
>LoadImagesFromLocal
|
||||
> LoadImagesFromLocal
|
||||
|
||||

|
||||
|
||||
|
||||
+10
-8
@@ -196,15 +196,17 @@ routes = web.RouteTableDef()
|
||||
async def mixlab_hander(request):
|
||||
config=os.path.join(current_path, "nodes/config.json")
|
||||
data={}
|
||||
# print(config)
|
||||
if os.path.exists(config):
|
||||
with open(config, 'r') as f:
|
||||
data = json.load(f)
|
||||
# print(data)
|
||||
try:
|
||||
if os.path.exists(config):
|
||||
with open(config, 'r') as f:
|
||||
data = json.load(f)
|
||||
# print(data)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return web.json_response(data)
|
||||
|
||||
@routes.post('/mixlab/workflow')
|
||||
async def mixlab_hander(request):
|
||||
async def mixlab_workflow_hander(request):
|
||||
data = await request.json()
|
||||
result={}
|
||||
try:
|
||||
@@ -276,8 +278,8 @@ NODE_CLASS_MAPPINGS = {
|
||||
"VAEDecodeConsistencyDecoder":VAEDecode,
|
||||
"ScreenShare":ScreenShareNode,
|
||||
"FloatingVideo":FloatingVideo,
|
||||
"CLIPSeg":CLIPSeg,
|
||||
"CombineMasks":CombineMasks
|
||||
"CLIPSeg_":CLIPSeg,
|
||||
"CombineMasks_":CombineMasks
|
||||
}
|
||||
|
||||
# 一个包含节点友好/可读的标题的字典
|
||||
|
||||
+70
-41
@@ -1,6 +1,6 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
from PIL import Image, ImageOps,ImageFilter,ImageEnhance,ImageDraw
|
||||
from PIL import Image, ImageOps,ImageFilter,ImageEnhance,ImageDraw,ImageSequence
|
||||
from PIL.PngImagePlugin import PngInfo
|
||||
import base64,os
|
||||
from io import BytesIO
|
||||
@@ -153,25 +153,48 @@ def get_not_transparent_area(image):
|
||||
return (x, y, w, h)
|
||||
|
||||
|
||||
|
||||
# 读取不了分层
|
||||
def load_psd(image):
|
||||
layers=[]
|
||||
print('load_psd',image.format)
|
||||
if image.format=='PSD':
|
||||
layers = [frame.copy() for frame in ImageSequence.Iterator(image)]
|
||||
print('#PSD',len(layers))
|
||||
else:
|
||||
image = ImageOps.exif_transpose(image) #校对方向
|
||||
layers.append(image)
|
||||
return layers
|
||||
|
||||
|
||||
def load_image(fp,white_bg=False):
|
||||
i = Image.open(fp)
|
||||
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)
|
||||
if white_bg==True:
|
||||
nw = mask.unsqueeze(0).unsqueeze(-1).repeat(1, 1, 1, 3)
|
||||
# 将mask的黑色部分对image进行白色处理
|
||||
image[nw == 1] = 1.0
|
||||
else:
|
||||
mask = torch.zeros((64,64), dtype=torch.float32, device="cpu")
|
||||
return (image,mask)
|
||||
im = Image.open(fp)
|
||||
|
||||
# ims=load_psd(im)
|
||||
im = ImageOps.exif_transpose(im) #校对方向
|
||||
ims=[im]
|
||||
|
||||
images=[]
|
||||
|
||||
for i in ims:
|
||||
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)
|
||||
if white_bg==True:
|
||||
nw = mask.unsqueeze(0).unsqueeze(-1).repeat(1, 1, 1, 3)
|
||||
# 将mask的黑色部分对image进行白色处理
|
||||
image[nw == 1] = 1.0
|
||||
else:
|
||||
mask = torch.zeros((64,64), dtype=torch.float32, device="cpu")
|
||||
|
||||
images.append({
|
||||
"image":image,
|
||||
"mask":mask
|
||||
})
|
||||
|
||||
return images
|
||||
|
||||
|
||||
# 获取图片s
|
||||
@@ -183,23 +206,27 @@ def get_images_filepath(f,white_bg=False):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
(im,mask)=load_image(file_path,white_bg)
|
||||
images.append({
|
||||
"image":im,
|
||||
"mask":mask,
|
||||
"file_path":file_path
|
||||
})
|
||||
imgs=load_image(file_path,white_bg)
|
||||
for img in imgs:
|
||||
images.append({
|
||||
"image":img['image'],
|
||||
"mask":img['mask'],
|
||||
"file_path":file_path,
|
||||
"psd":len(imgs)>1
|
||||
})
|
||||
except:
|
||||
print('非图片',file_path)
|
||||
|
||||
elif os.path.isfile(f):
|
||||
try:
|
||||
(im,mask)=load_image(f,white_bg)
|
||||
images.append({
|
||||
"image":im,
|
||||
"mask":mask,
|
||||
"file_path":f
|
||||
})
|
||||
imgs=load_image(f,white_bg)
|
||||
for img in imgs:
|
||||
images.append({
|
||||
"image":img['image'],
|
||||
"mask":img['mask'],
|
||||
"file_path":file_path,
|
||||
"psd":len(imgs)>1
|
||||
})
|
||||
except:
|
||||
print('非图片',f)
|
||||
else:
|
||||
@@ -583,43 +610,45 @@ class LoadImagesFromPath:
|
||||
"white_bg": (["disable","enable"],),
|
||||
"newest_files": (["enable", "disable"],),
|
||||
"index_variable":("INT", {
|
||||
"default": -1,
|
||||
"default": 0,
|
||||
"min": -1, #Minimum value
|
||||
"max": 2048, #Maximum value
|
||||
"step": 1, #Slider's step
|
||||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||||
}),
|
||||
"watcher":(["disable","enable"],),
|
||||
"result": ("WATCHER",),
|
||||
"result": ("WATCHER",),#为了激活本节点运行
|
||||
"prompt": ("PROMPT",),
|
||||
# "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ('IMAGE','MASK',)
|
||||
RETURN_TYPES = ('IMAGE','MASK','STRING')
|
||||
|
||||
FUNCTION = "run"
|
||||
|
||||
CATEGORY = "Mixlab/image"
|
||||
|
||||
# INPUT_IS_LIST = True
|
||||
OUTPUT_IS_LIST = (True,True,)
|
||||
OUTPUT_IS_LIST = (True,True,False,)
|
||||
|
||||
global watcher_folder
|
||||
watcher_folder=None
|
||||
|
||||
# 运行的函数
|
||||
def run(self,file_path,white_bg,newest_files,index_variable,watcher,result):
|
||||
def run(self,file_path,white_bg,newest_files,index_variable,watcher,result,prompt):
|
||||
global watcher_folder
|
||||
# print('###监听:',watcher_folder,watcher,file_path,result)
|
||||
|
||||
if watcher=='enable':
|
||||
if watcher_folder==None:
|
||||
watcher_folder = FolderWatcher(file_path)
|
||||
|
||||
if watcher_folder==None:
|
||||
watcher_folder = FolderWatcher(file_path)
|
||||
|
||||
watcher_folder.set_folder_path(file_path)
|
||||
|
||||
if watcher=='enable':
|
||||
# 在这里可以进行其他操作,监听会在后台持续
|
||||
watcher_folder.set_folder_path(file_path)
|
||||
watcher_folder.start()
|
||||
|
||||
else:
|
||||
if watcher_folder!=None:
|
||||
watcher_folder.stop()
|
||||
@@ -642,8 +671,8 @@ class LoadImagesFromPath:
|
||||
imgs=[imgs[index_variable]] if index_variable < len(imgs) else None
|
||||
masks=[masks[index_variable]] if index_variable < len(masks) else None
|
||||
|
||||
|
||||
return (imgs,masks,)
|
||||
print('#prompt::::',prompt)
|
||||
return (imgs,masks,prompt,)
|
||||
|
||||
|
||||
# TODO 扩大选区的功能,重新输出mask
|
||||
|
||||
+27
-17
@@ -8,25 +8,34 @@ import os
|
||||
# print('Watcher:',current_directory)
|
||||
|
||||
def save_to_json(file_path, data):
|
||||
with open(file_path, 'w') as f:
|
||||
json.dump(data, f)
|
||||
try:
|
||||
with open(file_path, 'w') as f:
|
||||
json.dump(data, f)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def read_from_json(file_path):
|
||||
with open(file_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
data={}
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return data
|
||||
|
||||
|
||||
# read_from_json()
|
||||
current_path = os.path.abspath(os.path.dirname(__file__))
|
||||
config_json=os.path.join(current_path,'config.json')
|
||||
print('Watcher:',config_json)
|
||||
# print('Watcher:',config_json)
|
||||
|
||||
def read_config():
|
||||
config={}
|
||||
if os.path.exists(config_json):
|
||||
# print('exists')
|
||||
config=read_from_json(config_json)
|
||||
try:
|
||||
if os.path.exists(config_json):
|
||||
config=read_from_json(config_json)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return config
|
||||
|
||||
|
||||
@@ -39,10 +48,10 @@ class FolderWatcher:
|
||||
config['folder_path']=folder_path
|
||||
save_to_json(config_json,config)
|
||||
|
||||
# self.observer = Observer()
|
||||
self.observer = None
|
||||
self.event_handler = self._create_event_handler()
|
||||
self.status = "Not started"
|
||||
self.event_type=''
|
||||
self.event_type='-'
|
||||
|
||||
def _create_event_handler(self):
|
||||
|
||||
@@ -77,22 +86,23 @@ class FolderWatcher:
|
||||
config=read_config()
|
||||
config['folder_path']=new_folder_path
|
||||
save_to_json(config_json,config)
|
||||
self.event_type=''
|
||||
self.event_type='-'
|
||||
|
||||
def start(self):
|
||||
self.observer = Observer()
|
||||
self.observer.schedule(self.event_handler, self.folder_path, recursive=True)
|
||||
self.observer.start()
|
||||
self.status = "Listening"
|
||||
self.event_type=''
|
||||
self.event_type='-'
|
||||
print('Listening')
|
||||
|
||||
def stop(self):
|
||||
self.observer.stop()
|
||||
self.observer.join()
|
||||
self.observer=None
|
||||
self.status = "Stopped"
|
||||
self.event_type=''
|
||||
if self.observer!=None:
|
||||
self.observer.stop()
|
||||
self.observer.join()
|
||||
self.observer=None
|
||||
self.status = "Stopped"
|
||||
self.event_type='-'
|
||||
print('Stopped')
|
||||
|
||||
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
numpy
|
||||
pyOpenSSL
|
||||
watchdog
|
||||
watchdog
|
||||
opencv-python-headless
|
||||
matplotlib
|
||||
@@ -3,7 +3,7 @@ import { app } from '../../../scripts/app.js'
|
||||
const repoOwner = 'shadowcz007' // 替换为仓库的所有者
|
||||
const repoName = 'comfyui-mixlab-nodes' // 替换为仓库的名称
|
||||
|
||||
const version='v0.2.1'
|
||||
const version='v0.2.4'
|
||||
|
||||
|
||||
fetch(`https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`)
|
||||
|
||||
+215
-39
@@ -29,6 +29,36 @@ async function interrupt () {
|
||||
})
|
||||
}
|
||||
|
||||
async function clipboardWriteImage (win, url) {
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
// console.log(url)
|
||||
const img = await createImage(url)
|
||||
// console.log(img)
|
||||
canvas.width = img.naturalWidth
|
||||
canvas.height = img.naturalHeight
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.drawImage(img, 0, 0)
|
||||
// 将canvas转为blob
|
||||
canvas.toBlob(async blob => {
|
||||
const data = [
|
||||
new ClipboardItem({
|
||||
[blob.type]: blob
|
||||
})
|
||||
]
|
||||
|
||||
win.navigator.clipboard
|
||||
.write(data)
|
||||
.then(() => {
|
||||
console.log('Image copied to clipboard')
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to copy image to clipboard:', error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function uploadFile (file) {
|
||||
try {
|
||||
const body = new FormData()
|
||||
@@ -402,6 +432,7 @@ const base64Df =
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.image.ScreenShareNode',
|
||||
async getCustomWidgets (app) {
|
||||
console.log('#Mixlab.image.ScreenShareNode', app)
|
||||
return {
|
||||
CHEESE (node, inputName, inputData, app) {
|
||||
// We return an object containing a field CHEESE which has a function (taking node, name, data, app)
|
||||
@@ -419,8 +450,8 @@ app.registerExtension({
|
||||
return window._mixlab_screen_imagePath || base64Df
|
||||
}
|
||||
}
|
||||
// widget.something = something; // maybe adds stuff to it
|
||||
node.addCustomWidget(widget) // adds it to the node
|
||||
// console.log('#Mixlab.image.ScreenShareNode',widget)
|
||||
node.addCustomWidget(widget)
|
||||
return widget // and returns it.
|
||||
},
|
||||
PROMPT (node, inputName, inputData, app) {
|
||||
@@ -439,7 +470,7 @@ app.registerExtension({
|
||||
return window._mixlab_screen_prompt || ''
|
||||
}
|
||||
}
|
||||
console.log('###widget', widget)
|
||||
// console.log('###widget', widget)
|
||||
node.addCustomWidget(widget) // adds it to the node
|
||||
return widget // and returns it.
|
||||
}
|
||||
@@ -800,6 +831,7 @@ app.registerExtension({
|
||||
|
||||
widget.preview = $el('video', {
|
||||
controls: true,
|
||||
draggable: true,
|
||||
style: {
|
||||
width: '100%'
|
||||
},
|
||||
@@ -807,6 +839,28 @@ app.registerExtension({
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAAXNSR0IArs4c6QAAALZJREFUKFOFkLERwjAQBPdbgBkInECGaMLUQDsE0AkRVRAYWqAByxldPPOWHwnw4OBGye1p50UDSoA+W2ABLPN7i+C5dyC6R/uiAUXRQCs0bXoNIu4QPQzAxDKxHoALOrZcqtiyR/T6CXw7+3IGHhkYcy6BOR2izwT8LptG8rbMiCRAUb+CQ6WzQVb0SNOi5Z2/nX35DRyb/ENazhpWKoGwrpD6nICp5c2qogc4of+c7QcrhgF4Aa/aoAFHiL+RAAAAAElFTkSuQmCC'
|
||||
})
|
||||
|
||||
// })
|
||||
// const dropTarget = document.getElementById('your-drop-target-id')
|
||||
|
||||
// dropTarget.addEventListener('dragover', event => {
|
||||
// event.preventDefault()
|
||||
// })
|
||||
|
||||
// dropTarget.addEventListener('drop', event => {
|
||||
// event.preventDefault()
|
||||
|
||||
// const imageUrl = event.dataTransfer.getData('text/plain')
|
||||
|
||||
// navigator.clipboard
|
||||
// .writeText(imageUrl)
|
||||
// .then(() => {
|
||||
// console.log('Image URL copied to clipboard')
|
||||
// })
|
||||
// .catch(error => {
|
||||
// console.error('Failed to copy image URL to clipboard:', error)
|
||||
// })
|
||||
// })
|
||||
|
||||
widget.canvas = $el('canvas', {
|
||||
style: {
|
||||
display: 'none'
|
||||
@@ -817,7 +871,6 @@ app.registerExtension({
|
||||
innerText: 'PictureInPicture',
|
||||
style: {
|
||||
display: 'pictureInPictureEnabled' in document ? 'block' : 'none',
|
||||
|
||||
cursor: 'pointer',
|
||||
padding: '8px 0',
|
||||
fontWeight: '300',
|
||||
@@ -830,6 +883,28 @@ app.registerExtension({
|
||||
widget.card.appendChild(widget.preview)
|
||||
widget.card.appendChild(widget.canvas)
|
||||
|
||||
widget.preview.addEventListener('click', event => {
|
||||
const imageUrl = window._mixlab_screen_result || ''
|
||||
// console.log(imageUrl)
|
||||
try {
|
||||
if (imageUrl) clipboardWriteImage(pipWindow, imageUrl)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
if (imageUrl) clipboardWriteImage(window, imageUrl)
|
||||
}
|
||||
|
||||
// pipWindow.navigator.permissions
|
||||
// .query({ name: 'clipboard-write' })
|
||||
// .then(result => {
|
||||
// if (result.state === 'granted' || result.state === 'prompt') {
|
||||
// // 执行复制操作
|
||||
|
||||
// } else {
|
||||
// console.error('Clipboard write permission denied')
|
||||
// }
|
||||
// })
|
||||
})
|
||||
|
||||
// widget.card.appendChild(widget.PictureInPicture)
|
||||
|
||||
widget.PictureInPicture.addEventListener('click', async () => {
|
||||
@@ -873,7 +948,17 @@ app.registerExtension({
|
||||
width: calc(100% - 24px);
|
||||
margin: 12px;`
|
||||
|
||||
// console.log(pipWindow.document)
|
||||
let inputDiv = document.createElement('div')
|
||||
// inputDiv.style = ``
|
||||
let infoDiv = document.createElement('div')
|
||||
infoDiv.style = ` width: 100%;
|
||||
height: 16px;
|
||||
color: white;
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
text-shadow: 1px 1px gray;`
|
||||
infoDiv.id = 'info'
|
||||
|
||||
// Move the player to the Picture-in-Picture window.
|
||||
let input = document.createElement('textarea')
|
||||
input.style = `
|
||||
@@ -927,8 +1012,14 @@ app.registerExtension({
|
||||
} else {
|
||||
input.style.display = 'none'
|
||||
}
|
||||
try {
|
||||
pipWindow.document.querySelector('#info').innerText = ''
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
|
||||
// TODO 需要判断是否有screenshare节点,没有的话,不需要添加
|
||||
let pauseBtn = document.createElement('butotn')
|
||||
pauseBtn.innerText = '⏸'
|
||||
pauseBtn.style = `cursor: pointer;height: 24px;margin:4px;
|
||||
@@ -949,6 +1040,13 @@ app.registerExtension({
|
||||
if (w) {
|
||||
w.liveBtn.innerText = 'Live Run'
|
||||
}
|
||||
|
||||
try {
|
||||
pipWindow.document.querySelector('#info').innerText =
|
||||
'Stop Live'
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
} else {
|
||||
pauseBtn.innerText = '⏸'
|
||||
let node = this.graph._nodes.filter(
|
||||
@@ -960,6 +1058,12 @@ app.registerExtension({
|
||||
window._mixlab_stopLive = await startLive(w.liveBtn)
|
||||
console.log('window._mixlab_stopLive', window._mixlab_stopLive)
|
||||
}
|
||||
|
||||
try {
|
||||
pipWindow.document.querySelector('#info').innerText = 'Live'
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -971,30 +1075,92 @@ app.registerExtension({
|
||||
window._mixlab_screen_prompt =
|
||||
window._mixlab_screen_prompt_input || window._mixlab_screen_prompt
|
||||
document.querySelector('#queue-button').click()
|
||||
|
||||
try {
|
||||
pipWindow.document.querySelector('#info').innerText =
|
||||
'Update Prompt'
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
|
||||
widget.preview.addEventListener('click', event => {
|
||||
const imageUrl = window._mixlab_screen_result || ''
|
||||
// console.log(imageUrl)
|
||||
try {
|
||||
if (imageUrl) clipboardWriteImage(pipWindow, imageUrl)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
if (imageUrl) clipboardWriteImage(window, imageUrl)
|
||||
}
|
||||
|
||||
try {
|
||||
pipWindow.document.querySelector('#info').innerText =
|
||||
'Image copied to clipboard'
|
||||
setTimeout(
|
||||
() =>
|
||||
(pipWindow.document.querySelector('#info').innerText = ''),
|
||||
8000
|
||||
)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
// pipWindow.navigator.permissions
|
||||
// .query({ name: 'clipboard-write' })
|
||||
// .then(result => {
|
||||
// if (result.state === 'granted' || result.state === 'prompt') {
|
||||
// // 执行复制操作
|
||||
|
||||
// } else {
|
||||
// console.error('Clipboard write permission denied')
|
||||
// }
|
||||
// })
|
||||
})
|
||||
|
||||
pipWindow.document.body.append(widget.preview)
|
||||
pipWindow.document.body.append(div)
|
||||
// console.log(pipWindow)
|
||||
|
||||
div.appendChild(btnDiv)
|
||||
btnDiv.appendChild(btn)
|
||||
btnDiv.appendChild(pauseBtn)
|
||||
btnDiv.appendChild(promptFinishBtn)
|
||||
div.appendChild(input)
|
||||
|
||||
// 输入框
|
||||
div.appendChild(inputDiv)
|
||||
inputDiv.appendChild(infoDiv)
|
||||
inputDiv.appendChild(input)
|
||||
|
||||
input.addEventListener('input', () => {
|
||||
window._mixlab_screen_prompt_input = input.value
|
||||
try {
|
||||
pipWindow.document.querySelector('#info').innerText = ''
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
|
||||
input.addEventListener('keydown', handleKeyDown)
|
||||
|
||||
function handleKeyDown (event) {
|
||||
if (event.key === 'Enter') {
|
||||
console.log('##更新Prompt')
|
||||
window._mixlab_screen_prompt =
|
||||
window._mixlab_screen_prompt_input ||
|
||||
window._mixlab_screen_prompt
|
||||
document.querySelector('#queue-button').click()
|
||||
if (!event.shiftKey) {
|
||||
// 回车键被按下且未同时按下Shift键,执行你的操作
|
||||
event.preventDefault() // 阻止默认行为(如提交表单)
|
||||
// 在这里添加你的代码
|
||||
console.log('##更新Prompt')
|
||||
window._mixlab_screen_prompt =
|
||||
window._mixlab_screen_prompt_input ||
|
||||
window._mixlab_screen_prompt
|
||||
document.querySelector('#queue-button').click()
|
||||
|
||||
try {
|
||||
pipWindow.document.querySelector('#info').innerText =
|
||||
'Update Prompt'
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1029,7 +1195,11 @@ app.registerExtension({
|
||||
const videoTrack = stream.getVideoTracks()[0]
|
||||
|
||||
video.preview.srcObject = new MediaStream([videoTrack])
|
||||
video.preview.play()
|
||||
try {
|
||||
video.preview.play()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
// 检查浏览器是否支持画中画模式
|
||||
if ('pictureInPictureEnabled' in document) {
|
||||
@@ -1062,7 +1232,7 @@ app.registerExtension({
|
||||
const context = canvas.getContext('2d')
|
||||
|
||||
if (message?.images_) {
|
||||
const base64 = message.images_[0]
|
||||
window._mixlab_screen_result = `data:image/png;base64,${message.images_[0]}`
|
||||
const image = new Image()
|
||||
image.onload = function () {
|
||||
canvas.width = image.width
|
||||
@@ -1070,7 +1240,7 @@ app.registerExtension({
|
||||
context.drawImage(image, 0, 0)
|
||||
}
|
||||
// console.log(`data:image/jpeg;base64,${base64}`)
|
||||
image.src = `data:image/jpeg;base64,${base64}`
|
||||
image.src = window._mixlab_screen_result
|
||||
}
|
||||
const onRemoved = this.onRemoved
|
||||
this.onRemoved = () => {
|
||||
@@ -1437,24 +1607,30 @@ function getURLParameters (url) {
|
||||
|
||||
const node = {
|
||||
name: 'RandomPrompt',
|
||||
async init (app) {
|
||||
// Any initial setup to run as soon as the page loads
|
||||
console.log('[logging]', 'extension init')
|
||||
|
||||
if (window.location.href.match('/?')) {
|
||||
const { workflow } = getURLParameters(window.location.href)
|
||||
if (workflow)
|
||||
get_my_workflow().then(data => {
|
||||
console.log('#get_my_workflow', data)
|
||||
let my_workflow = data.filter(
|
||||
d => d.filename == 'my_workflow.json'
|
||||
)[0]
|
||||
if (my_workflow?.data) {
|
||||
// app.loadGraphData(my_workflow.data)
|
||||
localStorage.setItem('workflow', JSON.stringify(my_workflow.data))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
async setup (a) {
|
||||
for (const node of app.graph._nodes) {
|
||||
// console.log('#setup', node)
|
||||
console.log('#setup', node)
|
||||
if (node.type === 'RandomPrompt') {
|
||||
updateUI(node)
|
||||
if (window.location.href.match('/?')) {
|
||||
const { workflow } = getURLParameters(window.location.href)
|
||||
if (workflow)
|
||||
get_my_workflow().then(data => {
|
||||
console.log('#get_my_workflow', data)
|
||||
let my_workflow = data.filter(
|
||||
d => d.filename == 'my_workflow.json'
|
||||
)[0]
|
||||
if (my_workflow?.data) {
|
||||
app.loadGraphData(my_workflow.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log('[logging]', 'loaded graph node: ', exportGraph(app.graph))
|
||||
@@ -1505,17 +1681,17 @@ const node = {
|
||||
// 汉化
|
||||
// app.graph._nodes // title ='123'
|
||||
|
||||
if (nodeData.name === 'SaveTransparentImage') {
|
||||
const onExecuted = nodeType.prototype.onExecuted
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
const r = onExecuted?.apply?.(this, arguments)
|
||||
console.log('executed', message)
|
||||
const { image_path } = message
|
||||
if (image_path) {
|
||||
}
|
||||
return r
|
||||
}
|
||||
}
|
||||
// if (nodeData.name === 'SaveTransparentImage') {
|
||||
// const onExecuted = nodeType.prototype.onExecuted
|
||||
// nodeType.prototype.onExecuted = function (message) {
|
||||
// const r = onExecuted?.apply?.(this, arguments)
|
||||
// console.log('executed', message)
|
||||
// const { image_path } = message
|
||||
// if (image_path) {
|
||||
// }
|
||||
// return r
|
||||
// }
|
||||
// }
|
||||
|
||||
if (nodeData.name === 'WSServer') {
|
||||
// Create the button widget for selecting the files
|
||||
|
||||
@@ -14,6 +14,10 @@ async function getConfig () {
|
||||
return await res.json()
|
||||
}
|
||||
|
||||
if (!window._mixlab_screen_prompt)
|
||||
window._mixlab_screen_prompt =
|
||||
'beautiful scenery nature glass bottle landscape,under water'
|
||||
|
||||
function get_position_style (ctx, widget_width, y, node_height) {
|
||||
const MARGIN = 4 // the margin around the html element
|
||||
|
||||
@@ -57,7 +61,28 @@ app.registerExtension({
|
||||
name: inputName, // the name, slice
|
||||
size: [128, 24], // a default size
|
||||
draw (ctx, node, width, y) {
|
||||
// a method to draw the widget (ctx is a CanvasRenderingContext2D)
|
||||
// // 绘制文件图标的函数
|
||||
// function drawFileIcon () {
|
||||
// // 清空画布
|
||||
// // ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
// // 绘制文件外框
|
||||
// ctx.fillStyle = '#000'
|
||||
// ctx.fillRect(5, 5, 40, 40)
|
||||
|
||||
// // 绘制文件夹图标
|
||||
// ctx.fillStyle = '#f00'
|
||||
// ctx.fillRect(10, 15, 30, 20)
|
||||
|
||||
// // 绘制监听符号
|
||||
// ctx.beginPath()
|
||||
// ctx.arc(30, 35, 5, 0, 2 * Math.PI)
|
||||
// ctx.fillStyle = '#00f'
|
||||
// ctx.fill()
|
||||
// }
|
||||
|
||||
// // 调用绘制函数
|
||||
// drawFileIcon()
|
||||
},
|
||||
computeSize (...args) {
|
||||
return [128, 24] // a method to compute the current size of the widget
|
||||
@@ -69,6 +94,26 @@ app.registerExtension({
|
||||
// widget.something = something; // maybe adds stuff to it
|
||||
node.addCustomWidget(widget) // adds it to the node
|
||||
return widget // and returns it.
|
||||
},
|
||||
PROMPT (node, inputName, inputData, app) {
|
||||
// console.log('node', inputName, inputData[0])
|
||||
const widget = {
|
||||
type: inputData[0], // the type, CHEESE
|
||||
name: inputName, // the name, slice
|
||||
size: [128, 24], // a default size
|
||||
draw (ctx, node, width, y) {
|
||||
// a method to draw the widget (ctx is a CanvasRenderingContext2D)
|
||||
},
|
||||
computeSize (...args) {
|
||||
return [128, 24] // a method to compute the current size of the widget
|
||||
},
|
||||
async serializeValue (nodeId, widgetIndex) {
|
||||
return window._mixlab_screen_prompt || ''
|
||||
}
|
||||
}
|
||||
// widget.something = something; // maybe adds stuff to it
|
||||
node.addCustomWidget(widget) // adds it to the node
|
||||
return widget // and returns it.
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -79,11 +124,7 @@ app.registerExtension({
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
orig_nodeCreated?.apply(this, arguments)
|
||||
|
||||
|
||||
// console.log(
|
||||
// 'watch widtget',
|
||||
// this.widgets.filter(w => w.name == 'watcher')[0]
|
||||
// )
|
||||
console.log('watch widtget', this.widgets)
|
||||
|
||||
const watcher = this.widgets.filter(w => w.name == 'watcher')[0]
|
||||
|
||||
@@ -111,7 +152,6 @@ app.registerExtension({
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 上次路径填充
|
||||
getConfig().then(json => {
|
||||
let w = this.widgets.filter(w => w.name == 'file_path')[0]
|
||||
@@ -120,7 +160,6 @@ app.registerExtension({
|
||||
}
|
||||
// console.log(json.event_type)
|
||||
window._mixlab_file_path_watcher = json.event_type
|
||||
|
||||
})
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"last_node_id": 23,
|
||||
"last_link_id": 47,
|
||||
"last_link_id": 48,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 11,
|
||||
@@ -94,7 +94,7 @@
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
882790958612696,
|
||||
1088992701378297,
|
||||
"randomize",
|
||||
4,
|
||||
1.6,
|
||||
@@ -110,10 +110,10 @@
|
||||
-470,
|
||||
840
|
||||
],
|
||||
"size": [
|
||||
430.924072265625,
|
||||
253.48239135742188
|
||||
],
|
||||
"size": {
|
||||
"0": 430.924072265625,
|
||||
"1": 253.48239135742188
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
@@ -212,7 +212,7 @@
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -271,45 +271,6 @@
|
||||
"control_scribble-fp16.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
678,
|
||||
-77
|
||||
],
|
||||
"size": {
|
||||
"0": 400,
|
||||
"1": 200
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 32
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
39
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"superman,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
@@ -322,7 +283,7 @@
|
||||
"1": 200
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -361,7 +322,7 @@
|
||||
"1": 126
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -465,7 +426,7 @@
|
||||
"1": 246
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
@@ -512,6 +473,53 @@
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
678,
|
||||
-77
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 32
|
||||
},
|
||||
{
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"link": 48,
|
||||
"widget": {
|
||||
"name": "text"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
39
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"superman,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"type": "LoadImagesFromPath",
|
||||
@@ -521,7 +529,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 202
|
||||
"1": 238
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
@@ -542,6 +550,15 @@
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 6
|
||||
},
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
48
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
@@ -813,6 +830,14 @@
|
||||
18,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
48,
|
||||
22,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"STRING"
|
||||
]
|
||||
],
|
||||
"groups": [
|
||||
|
||||
Reference in New Issue
Block a user