Compare commits

..
24 Commits
Author SHA1 Message Date
shadowcz007 52c38b10dd v0.28.2 2024-05-23 18:19:30 +08:00
shadowcz007 7047aa5456 add video format 2024-05-23 16:59:04 +08:00
shadowcz007 33fe4019f7 Update ui_mixlab.js 2024-05-23 16:43:50 +08:00
shadowcz007 80b9d97690 Update Video.py 2024-05-23 15:58:24 +08:00
shadowcz007 3c3c92723f Update pyproject.toml 2024-05-23 10:34:36 +08:00
shadowcz007 037bd87006 Update pyproject.toml 2024-05-23 10:26:48 +08:00
shadowcz007 f688310d28 Update Utils.py 2024-05-23 10:14:25 +08:00
shadow c4d65e7a45 Merge pull request #234 from haohaocreates/publish
Add Github Action for Publishing to Comfy Registry
2024-05-22 23:14:33 +08:00
shadow 6f208b710d Merge pull request #235 from haohaocreates/pyproject
Add pyproject.toml for Custom Node Registry
2024-05-22 23:14:17 +08:00
haohaocreates b599faaf85 Update pyproject.toml desc 2024-05-21 15:24:07 -04:00
haohaocreates 6d991d20dc chore(publish): Add Github Action for Publishing to Comfy Registry 2024-05-21 19:19:01 +00:00
haohaocreates c87e0296f6 chore(pyproject): Add pyproject.toml for Custom Node Registry 2024-05-21 19:19:01 +00:00
shadow 16cdb4c5b4 Merge pull request #231 from 295958090/main
修复FloatSlider的bug
2024-05-21 21:57:10 +08:00
Bai Shui 7631b8924d 修复bug 2024-05-21 13:34:29 +08:00
shadowcz007 785d307ff3 Update index.html 2024-05-18 16:13:30 +08:00
shadowcz007 8c713ff35e Update index.html 2024-05-18 16:08:25 +08:00
shadowcz007 7d80493bef Update index.html 2024-05-18 16:05:39 +08:00
shadowcz007 bff2760c3d v0.28.1
修复bug
2024-05-18 11:38:50 +08:00
shadowcz007 a0f8848367 修复 当上传新的图片,编辑mask的bug 2024-05-18 11:38:28 +08:00
shadowcz007 5b1cbcd8d5 修复bug 2024-05-16 13:20:06 +08:00
shadowcz007 05857a92d5 v0.28.0
add rembg api & webapp rembg
2024-05-16 11:49:45 +08:00
shadowcz007 6bdc811286 add rembg api & webapp rembg 2024-05-16 11:49:14 +08:00
shadowcz007 469d50a5b8 Update index.html 2024-05-16 09:02:13 +08:00
shadowcz007 ef86904bfb Update ui_mixlab.js 2024-05-16 09:02:08 +08:00
14 changed files with 453 additions and 98 deletions
+21
View File
@@ -0,0 +1,21 @@
name: Publish to Comfy registry
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "pyproject.toml"
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@main
with:
## Add your own personal access token to your Github Repository secrets and reference it here.
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
+70 -1
View File
@@ -8,6 +8,8 @@ import hashlib
import datetime
import folder_paths
import logging
import base64,io,re
from PIL import Image
from comfy.cli_args import args
python = sys.executable
@@ -30,6 +32,8 @@ except:
print("##nodes.ChatGPT ImportError")
from .nodes.RembgNode import get_rembg_models,U2NET_HOME,run_briarmbg,run_rembg
from server import PromptServer
try:
@@ -98,6 +102,26 @@ install_openai()
current_path = os.path.abspath(os.path.dirname(__file__))
def remove_base64_prefix(base64_str):
"""
去除 base64 字符串中的 data:image/*;base64, 前缀
Args:
base64_str: base64 编码的字符串
Returns:
去除前缀后的 base64 字符串
"""
# 使用正则表达式匹配常见的前缀
pattern = r'^data:image\/(.*);base64,(.+)$'
match = re.match(pattern, base64_str)
if match:
# 如果匹配到常见的前缀,则去除前缀并返回
return match.group(2)
else:
# 如果不匹配到常见的前缀,则直接返回
return base64_str
def calculate_md5(string):
encoded_string = string.encode()
@@ -629,10 +653,53 @@ async def get_checkpoints(request):
names=get_llama_models()
except:
print("llamafile none")
try:
if data['type']=='rembg':
names=get_rembg_models(U2NET_HOME)
except:
print("rembg none")
return web.json_response({"names":names,"types":list(folder_paths.folder_names_and_paths.keys())})
@routes.post('/mixlab/rembg')
async def rembg_hander(request):
data = await request.json()
model=data['model']
result={}
data_base64=remove_base64_prefix(data['base64'])
image_data = base64.b64decode(data_base64)
# 创建一个BytesIO对象
image_stream = io.BytesIO(image_data)
# 使用PIL Image模块读取图像
image = Image.open(image_stream)
if model=='briarmbg':
_,rgba_images,_=run_briarmbg([image])
else:
_,rgba_images,_=run_rembg(model,[image])
with io.BytesIO() as buf:
rgba_images[0].save(buf, format='PNG')
img_bytes = buf.getvalue()
img_base64 = base64.b64encode(img_bytes).decode('utf-8')
try:
result={
'data':img_base64,
'model':model,
'status':'success',
}
except Exception as e:
print(e)
return web.json_response(result)
@routes.post("/mixlab/prompt_result")
async def post_prompt_result(request):
data = await request.json()
@@ -711,12 +778,14 @@ async def start_local_llm(data):
server_settings=ServerSettings(host=address,port=port)
name, ext = os.path.splitext(os.path.basename(model))
print('#model',name)
app = create_app(
server_settings=server_settings,
model_settings=[
ModelSettings(
model=model,
model_alias=os.path.basename(model),
model_alias=name,
n_gpu_layers=n_gpu_layers,
n_ctx=4098,
chat_format=chat_format,
+28 -18
View File
@@ -476,6 +476,24 @@ os.environ["U2NET_HOME"] = U2NET_HOME
global _available
_available=False
def get_rembg_models(path):
"""从目录中获取文件并提取文件名
Args:
path: 目录路径
Returns:
文件名列表
"""
filenames = []
for root, _, files in os.walk(path):
for filename in files:
# 过滤隐藏文件
if not filename.startswith('.'):
name, ext = os.path.splitext(os.path.basename(filename))
filenames.append(name)
return filenames
def is_installed(package):
try:
spec = importlib.util.find_spec(package)
@@ -509,7 +527,7 @@ except:
_available=False
def briarmbg_run(images=[]):
def run_briarmbg(images=[]):
mroot=os.path.join(folder_paths.models_dir, "rembg")
m=os.path.join(mroot,'briarmbg.pth')
if os.path.exists(m)==False:
@@ -573,14 +591,15 @@ def briarmbg_run(images=[]):
return (masks,rgba_images,rgb_images)
def run_bg(model_name= "unet",images=[]):
def run_rembg(model_name= "unet",images=[],callback=None):
# model_name = "unet" # "isnet-general-use"
# print('#run_rembg',model_name)
rembg_session = new_session(model_name)
masks=[]
rgba_images=[]
rgb_images=[]
# 进度条
pbar = comfy.utils.ProgressBar(len(images) )
pbar=callback
for img in images:
# use the post_process_mask argument to post process the mask to get better results.
mask = remove(img, session=rembg_session,only_mask=True,post_process_mask=True)
@@ -620,8 +639,9 @@ def run_bg(model_name= "unet",images=[]):
rgb_image = Image.new("RGB", image_rgba.size, (0, 0, 0))
rgb_image.paste(image_rgba, mask=image_rgba.split()[3])
rgb_images.append(rgb_image)
pbar.update(1)
if pbar:
pbar.update(1)
return (masks,rgba_images,rgb_images)
@@ -643,17 +663,7 @@ class RembgNode_:
def INPUT_TYPES(s):
return {"required": {
"image": ("IMAGE",),
"model_name": ([
"briarmbg",
"u2net",
"u2netp",
"u2net_human_seg",
"u2net_cloth_seg",
"silueta",
"isnet-general-use",
"isnet-anime",
],),
"model_name": (get_rembg_models(U2NET_HOME),),
},
}
@@ -681,9 +691,9 @@ class RembgNode_:
images.append(im)
if model_name=='briarmbg':
masks,rgba_images,rgb_images=briarmbg_run(images)
masks,rgba_images,rgb_images=run_briarmbg(images)
else:
masks,rgba_images,rgb_images=run_bg(model_name,images)
masks,rgba_images,rgb_images=run_rembg(model_name,images, comfy.utils.ProgressBar(len(images) ))
masks=[pil2tensor(m) for m in masks]
+2 -4
View File
@@ -284,7 +284,7 @@ class FloatSlider:
}
RETURN_TYPES = ("FLOAT",)
RETURN_NAMES = ('weight(0-1)',)
RETURN_NAMES = ('FLOAT',)
FUNCTION = "run"
CATEGORY = "♾️Mixlab/Input"
@@ -297,9 +297,7 @@ class FloatSlider:
number = min_value
elif number > max_value:
number = max_value
scaled_number = (number - min_value) / (max_value - min_value)
return (scaled_number,)
return (number,)
class IntNumber:
@classmethod
+2 -1
View File
@@ -87,7 +87,7 @@ def split_video(video_path, video_segment_frames, transition_frames, output_dir)
folder_paths.folder_names_and_paths["video_formats"] = (
[
os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "video_formats"),
os.path.join(os.path.dirname(os.path.abspath(__file__)), ".", "video_formats"),
],
[".json"]
)
@@ -433,6 +433,7 @@ class VideoCombine_Adv:
ffmpeg_formats = ["video/"+x[:-5] for x in folder_paths.get_filename_list("video_formats")]
else:
ffmpeg_formats = []
# ffmpeg_formats =["video/"+x for x in ['webm', 'mp4', 'mkv']]
return {
"required": {
"image_batch": ("IMAGE",),
+10
View File
@@ -0,0 +1,10 @@
{
"main_pass":
[
"-n", "-c:v", "libsvtav1",
"-pix_fmt", "yuv420p10le",
"-crf", "23"
],
"extension": "webm",
"environment": {"SVT_LOG": "1"}
}
+9
View File
@@ -0,0 +1,9 @@
{
"main_pass":
[
"-n", "-c:v", "libx264",
"-pix_fmt", "yuv420p",
"-crf", "19"
],
"extension": "mp4"
}
+11
View File
@@ -0,0 +1,11 @@
{
"main_pass":
[
"-n", "-c:v", "libx265",
"-pix_fmt", "yuv420p10le",
"-preset", "medium",
"-crf", "22",
"-x265-params", "log-level=quiet"
],
"extension": "mp4"
}
+9
View File
@@ -0,0 +1,9 @@
{
"main_pass":
[
"-n",
"-pix_fmt", "yuv420p",
"-crf", "23"
],
"extension": "webm"
}
+15
View File
@@ -0,0 +1,15 @@
[project]
name = "comfyui-mixlab-nodes"
description = "3D, ScreenShareNode & FloatingVideoNode, SpeechRecognition & SpeechSynthesis, GPT, LoadImagesFromLocal, Layers, Other Nodes, ..."
version = "0.28.1"
license = "MIT"
dependencies = ["numpy", "pyOpenSSL", "watchdog", "opencv-python-headless", "matplotlib", "openai", "simple-lama-inpainting", "clip-interrogator==0.6.0", "transformers>=4.36.0", "lark-parser", "imageio-ffmpeg", "rembg[gpu]", "omegaconf==2.3.0", "Pillow>=9.5.0", "einops==0.7.0", "trimesh>=4.0.5", "huggingface-hub", "scikit-image"]
[project.urls]
Repository = "https://github.com/shadowcz007/comfyui-mixlab-nodes"
# Used by Comfy Registry https://comfyregistry.org
[tool.comfy]
PublisherId = "shadow"
DisplayName = "comfyui-mixlab-nodes"
Icon = ""
+255 -65
View File
@@ -247,7 +247,7 @@
.card textarea {
width: 100%;
height:'fit-content';
height: 'fit-content';
/* min-width: 300px; */
margin-top: 12px;
resize: none;
@@ -474,15 +474,14 @@
<a class="link" href="https://www.mixcomfy.com" target="_blank">ComfyUI中文爱好者社区推荐</a>
</div>
<a target="_blank" id="login_btn" href="https://www.mixcomfy.com/blog/" style="text-decoration: none;
<a id="login_btn" target="_blank" href="https://discord.gg/xbP2GZF6gn" style="text-decoration: none;
color: black;font-size:12px">
<svg height="32" aria-hidden="true" viewBox="0 0 16 16" version="1.1" width="32" data-view-component="true"
class="octicon octicon-mark-github v-align-middle color-fg-default">
<path
d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z">
</path>
</svg> Community</a>
</svg> HELP/帮助</a>
</div>
<a id="author"></a>
@@ -680,11 +679,89 @@
}
// 获取 rembg 模型
async function get_rembg_models() {
try {
const response = await fetch(`${get_url()}/mixlab/folder_paths`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'rembg'
})
})
const data = await response.json()
// console.log(data)
return data.names
} catch (error) {
console.error(error)
}
}
//自动抠图
async function run_rembg(model, base64) {
try {
const response = await fetch(`${get_url()}/mixlab/rembg`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
model,
base64
})
})
const data = await response.json()
// console.log(data)
return data.data
} catch (error) {
console.error(error)
}
}
function convertImageToBlackBasedOnAlpha(image) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Draw the image onto the canvas
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0);
// Get the image data from the canvas
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const pixels = imageData.data;
// Modify the RGB values based on the alpha channel
for (let i = 0; i < pixels.length; i += 4) {
const alpha = pixels[i + 3];
if (alpha !== 0) {
// Set non-transparent pixels to black
pixels[i] = 0; // Red
pixels[i + 1] = 0; // Green
pixels[i + 2] = 0; // Blue
}
}
// Put the modified image data back onto the canvas
ctx.putImageData(imageData, 0, 0);
// Convert the modified canvas to base64 data URL
const base64ImageData = canvas.toDataURL('image/png'); // Replace 'png' with your desired image format
return base64ImageData;
}
// 图像编辑
async function editImage(image, data) {
//判断mask是否有输出
let isMask = data.options.hasMask;
console.log(data)
//app
document.body.querySelector('.app').style.display = 'none'
document.body.querySelector('#author').style.display = 'none'
@@ -693,21 +770,139 @@
editor.style.display = 'block';
const iframe = editor.querySelector('iframe');
const sleep = (t = 1000) => {
return new Promise((res, rej) => {
setTimeout(() => {
res(true)
}, t)
})
}
//清空 图层
const removeAllLayer = () => {
let Layers = iframe.contentWindow.Layers;
//清空
Layers.reset_layers()
Layers.refresh_gui()
}
// 复原
const resetLayer = () => {
let Layers = iframe.contentWindow.Layers;
for (const layer of Layers.get_layers()) {
layer.visible = true;
}
Layers.refresh_gui()
}
//取image
const getImageBase64FromLayer = () => {
let Layers = iframe.contentWindow.Layers;
let tempCanvas = document.createElement("canvas");
let tempCtx = tempCanvas.getContext("2d");
let dim = Layers.get_dimensions();
tempCanvas.width = dim.width;
tempCanvas.height = dim.height;
for (const layer of Layers.get_layers()) {
if (layer.name === 'Image_' + data.id) {
layer.visible = true;
} else {
layer.visible = false;
}
}
Layers.refresh_gui()
Layers.convert_layers_to_canvas(tempCtx);
return tempCanvas.toDataURL()
}
//add mask
const addMask = (id, name, image) => {
let Layers = iframe.contentWindow.Layers;
var new_mask_layer = {
id,
name,
type: 'brush',
data: [],
render_function: ['brush', 'render'],
width: image.naturalWidth || image.width,
height: image.naturalHeight || image.height,
};
Layers.insert(new_mask_layer);
}
//add image
const addImage = (id, name, image) => {
let Layers = iframe.contentWindow.Layers;
var new_mask_layer = {
id,
name,
type: 'image',
data: image,
width: image.naturalWidth || image.width,
height: image.naturalHeight || image.height,
width_original: image.naturalWidth || image.width,
height_original: image.naturalHeight || image.height,
};
Layers.insert(new_mask_layer);
}
//默认的画笔size设置大
// let inputSize = (iframe.contentDocument.getElementById('size')).querySelector('input');
// inputSize.value=50;
// (iframe.contentDocument.getElementById('size')).querySelector('.increase_number').click()
//自动抠图
let autoMaskSelect = iframe.contentDocument.getElementById('automask_image_mixlab');
const select = iframe.contentDocument.getElementById('automask_models_mixlab');
if (select.children.length === 0) {
let rembgModels = await get_rembg_models()
// 遍历模型列表并创建选项
for (const model of rembgModels) {
const option = document.createElement('option');
option.value = model;
option.textContent = model;
select.appendChild(option);
}
}
let autoMaskBtn = iframe.contentDocument.getElementById('automask_image_mixlab');
if (!autoMaskBtn.getAttribute('init')) autoMaskBtn.addEventListener('click', async e => {
//api请求
let base64 = getImageBase64FromLayer()
resetLayer()
let res = await run_rembg(select.value, base64)
const match = res.match(/^data:image\/(\w+);base64,/);
if (!match) {
res = 'data:image/png;base64,' + res
}
let image = await createImage(res)
let mb = convertImageToBlackBasedOnAlpha(image)
let mask = await createImage(mb)
let id = Layers.auto_increment;
addImage(id, 'Mask_' + data.id + id, mask)
})
autoMaskBtn.setAttribute('init', 1)
let cancelImageBtn = iframe.contentDocument.getElementById('cancel_image_mixlab');
cancelImageBtn.addEventListener('click', e => {
if (!cancelImageBtn.getAttribute('init')) cancelImageBtn.addEventListener('click', e => {
editor.style.display = 'none';
document.body.querySelector('.app').style.display = 'flex'
document.body.querySelector('#author').style.display = 'block'
})
cancelImageBtn.setAttribute('init', 1)
// 获取 id 为 "mix" 的 button 元素
let saveImageBtn = iframe.contentDocument.getElementById('save_image_mixlab');
saveImageBtn.addEventListener('click', async e => {
saveImageBtn.style = `width: 98px;
height: 36px;
margin: 0 12px;
background-color: var(--background-color-active);
color: var(--text-color-active);`
if (!saveImageBtn.getAttribute('init')) saveImageBtn.addEventListener('click', async e => {
//保存,并更新图片
e.preventDefault();
@@ -721,6 +916,7 @@
tempCanvas.width = dim.width;
tempCanvas.height = dim.height;
//todo 获取Image更新后的数据(暂不支持image的修改)
for (const layer of Layers.get_layers()) {
if (layer.name !== 'Image_' + data.id) {
@@ -734,13 +930,7 @@
Layers.convert_layers_to_canvas(tempCtx);
// 复原
for (const layer of Layers.get_layers()) {
layer.visible = true;
}
Layers.refresh_gui()
resetLayer()
// 获取图像数据
const imageData = tempCtx.getImageData(0, 0, dim.width, dim.height);
@@ -766,10 +956,15 @@
// // 获取读取的文件内容,即 Blob 对象
let hashId = await calculateImageHash(fileBlob)
if (hashId == window._appData.data[data.id].hashId) return;
if (hashId == window._appData.data[data.id].hashId) {
document.body.querySelector('.app').style.display = 'flex'
document.body.querySelector('#author').style.display = 'block'
return;
}
//底图
const { url: imgurl } = await uploadImage(base64ToBlob(data.options.defaultImage))
//mask
let { url, name } = await uploadMask(fileBlob, imgurl);
// 在这里可以对 Blob 对象进行进一步处理
// imageElement.src = url;
@@ -777,31 +972,22 @@
window._appData.data[data.id].hashId = hashId;
// console.log("上传的文件:", url, data.id, name);
//更新图片
const canvas = document.createElement("canvas");
canvas.width = dim.width;
canvas.height = dim.height;
const ctx = canvas.getContext('2d');
const defaultImage = new Image();
defaultImage.src = data.options.defaultImage;
defaultImage.onload = function () {
ctx.drawImage(defaultImage, 0, 0, dim.width, dim.height);
const defaultImage = await createImage(data.options.defaultImage)
ctx.drawImage(defaultImage, 0, 0, dim.width, dim.height);
// 绘制base64图片
const base64Image = base64
const base64ImageObj = new Image();
base64ImageObj.onload = function () {
ctx.globalCompositeOperation = 'destination-in';
ctx.drawImage(base64ImageObj, 0, 0, dim.width, dim.height);
image.src = canvas.toDataURL();
};
base64ImageObj.src = base64;
};
// 绘制base64图片
// const base64Image = base64
const base64ImageObj = await createImage(base64)
ctx.globalCompositeOperation = 'destination-in';
ctx.drawImage(base64ImageObj, 0, 0, dim.width, dim.height);
image.src = canvas.toDataURL();
}
@@ -809,46 +995,34 @@
document.body.querySelector('#author').style.display = 'block'
})
saveImageBtn.setAttribute('init', 1)
var Layers = iframe.contentWindow.Layers;
// console.log(Layers)
//判断是否已经存在
let layers1 = Layers.get_layers()
let layers1 = Layers.get_layers();
if (!layers1.filter(l => l.name == 'Image_' + data.id)[0]) {
var new_layer = {
id: (Layers.get_layers()).length,
name: 'Image_' + data.id,
type: 'image',
data: image,
width: image.naturalWidth || image.width,
height: image.naturalHeight || image.height,
width_original: image.naturalWidth || image.width,
height_original: image.naturalHeight || image.height,
};
Layers.insert(new_layer);
//通过layer.link.src 判断是否图片更新
console.log(layers1.filter(l => l.name == 'Image_' + data.id)[0]?.link?.currentSrc !== data.options.defaultImage)
if (layers1.filter(l => l.name == 'Image_' + data.id)[0]
&& layers1.filter(l => l.name == 'Image_' + data.id)[0].link.src !== data.options.defaultImage) {
//清空图层
removeAllLayer();
layers1 = [];
await sleep()
}
let im = await createImage(data.options.defaultImage)
// console.log(layers1, layers1.length)
if (!layers1.filter(l => l.name == 'Image_' + data.id)[0]) {
addImage(0, 'Image_' + data.id, im)
}
if (isMask) {
if (!layers1.filter(l => l.name == 'Mask_' + data.id)[0]) {
var new_mask_layer = {
id: (Layers.get_layers()).length,
name: 'Mask_' + data.id,
type: 'brush',
data: [],
render_function: ['brush', 'render'],
width: image.naturalWidth || image.width,
height: image.naturalHeight || image.height,
};
Layers.insert(new_mask_layer);
addMask(1, 'Mask_' + data.id, im)
}
}
}
@@ -1297,8 +1471,9 @@
if (hashId == window._appData.data[data.id].hashId) return
let base64 = await blobToBase64(fileBlob)
if (data.class_type === 'LoadImagesToBatch') {
let base64 = await blobToBase64(fileBlob)
createBase64ImageForLoadImageToBatch(imageElement, data.id, base64)
} else {
let { url, name } = await uploadImage(fileBlob);
@@ -1307,6 +1482,14 @@
window._appData.data[data.id].inputs.image = name;
window._appData.data[data.id].hashId = hashId;
console.log("上传的文件:", url, data.id, name);
//更换option里的default image
window._appData.input = Array.from(window._appData.input, inp => {
if (inp.id === data.id) {
inp.options.defaultImage = base64;
}
return inp
})
}
}
}
@@ -1608,9 +1791,9 @@
//上传,返回url
let { url, name } = await uploadImage(fileBlob, '.' + file.type.split('/')[1])
let base64 = await parseImageToBase64(url);
if (data.class_type === 'ImagesPrompt_') {
//
let base64 = await parseImageToBase64(url);
uploadContainer.querySelector('.images_prompt_main').src = base64
window._appData.data[data.id].inputs.image_base64 = base64;
} else {
@@ -1620,10 +1803,17 @@
// 在这里可以对 Blob 对象进行进一步处理
imageElement.src = url;
if (isVideoUpload) {
window._appData.data[data.id].inputs.video = name;
} else {
//更换option里的default image
window._appData.input = Array.from(window._appData.input, inp => {
if (inp.id === data.id) {
inp.options.defaultImage = base64;
}
return inp
})
window._appData.data[data.id].inputs.image = name;
}
+1 -1
View File
@@ -3,7 +3,7 @@ import { app } from '../../../scripts/app.js'
const repoOwner = 'shadowcz007' // 替换为仓库的所有者
const repoName = 'comfyui-mixlab-nodes' // 替换为仓库的名称
const version = 'v0.27.1'
const version = 'v0.28.2'
fetch(`https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`)
.then(response => response.json())
+2 -6
View File
@@ -46,7 +46,7 @@ async function get_llamafile_models () {
})
const data = await response.json()
console.log(data)
// console.log(data)
return data.names
} catch (error) {
console.error(error)
@@ -539,10 +539,6 @@ injectCSS(`::-webkit-scrollbar {
border-left: 2px solid var(--input-text);
}
.litegraph{
background: var(--bg-color)!important;
}
`)
async function getCustomnodeMappings (mode = 'url') {
@@ -1361,7 +1357,7 @@ app.registerExtension({
? nodesMap
: await getCustomnodeMappings('url')
console.log('node & node map', node, nodesMap, nodesMap[node.type])
console.log("%c### node & node map", "background: yellow; color: black", node, nodesMap, nodesMap[node.type])
let repo = nodesMap[node.type]
if (repo) {
let markdown = await fetchReadmeContent(repo.url)
+18 -2
View File
@@ -45,6 +45,15 @@
<div class="submenu">
<!-- <a class="logo" href="#">miniPaint</a> -->
<div class="block attributes" id="action_attributes"></div>
<select id="automask_models_mixlab"></select>
<button id="automask_image_mixlab" type="button" style="width: 98px;
height: 36px;margin-right: 18px;
color: white;">
RemoveBg
</button>
<button id="cancel_image_mixlab" type="button" style="width: 98px;
height: 36px;
color: white;">
@@ -55,6 +64,13 @@
color: white;">
Save
</button>
<a
target="_blank" href="https://discord.gg/xbP2GZF6gn"
style="width: 98px;
color: white;
text-decoration: none;"> Help/帮助 </a>
<button class="undo_button" id="undo_button" type="button">
<span class="sr_only">Undo</span>
</button>
@@ -82,7 +98,7 @@
</div>
<div class="sidebar_right">
<div class="preview block">
<div class="preview block" style="display: none;">
<h2 class="trn toggle" data-target="toggle_preview">Preview</h2>
<div id="toggle_preview"></div>
</div>
@@ -92,7 +108,7 @@
<div class="content" id="toggle_colors"></div>
</div>
<div class="block" id="info_base">
<div class="block" id="info_base" style="display: none;">
<h2 class="trn toggle toggle-full" data-target="toggle_info">Information</h2>
<div class="content" id="toggle_info"></div>
</div>