feat: update external image node to have default value

This commit is contained in:
bennykok 2025-01-07 21:03:52 +08:00
parent 6ed468d7d4
commit bf00580562
2 changed files with 182 additions and 89 deletions

View File

@ -21,8 +21,9 @@ class ComfyUIDeployExternalImage:
), ),
"description": ( "description": (
"STRING", "STRING",
{"multiline": True, "default": ""}, {"multiline": False, "default": ""},
), ),
"default_value_url": ("STRING", {"image_preview": True, "default": ""}),
} }
} }
@ -33,31 +34,43 @@ class ComfyUIDeployExternalImage:
CATEGORY = "image" CATEGORY = "image"
def run(self, input_id, default_value=None, display_name=None, description=None): def run(self, input_id, default_value=None, display_name=None, description=None, default_value_url=None):
image = default_value image = default_value
# Try both input_id and default_value_url
urls_to_try = [url for url in [input_id, default_value_url] if url]
print(default_value_url)
for url in urls_to_try:
try: try:
if input_id.startswith('http'): if url.startswith('http'):
import requests import requests
from io import BytesIO from io import BytesIO
print("Fetching image from url: ", input_id) print(f"Fetching image from url: {url}")
response = requests.get(input_id) response = requests.get(url)
image = Image.open(BytesIO(response.content)) image = Image.open(BytesIO(response.content))
elif input_id.startswith('data:image/png;base64,') or input_id.startswith('data:image/jpeg;base64,') or input_id.startswith('data:image/jpg;base64,'): break
elif url.startswith(('data:image/png;base64,', 'data:image/jpeg;base64,', 'data:image/jpg;base64,')):
import base64 import base64
from io import BytesIO from io import BytesIO
print("Decoding base64 image") print("Decoding base64 image")
base64_image = input_id[input_id.find(",")+1:] base64_image = url[url.find(",")+1:]
decoded_image = base64.b64decode(base64_image) decoded_image = base64.b64decode(base64_image)
image = Image.open(BytesIO(decoded_image)) image = Image.open(BytesIO(decoded_image))
else: break
raise ValueError("Invalid image url provided.") except:
continue
if image is not None:
try:
image = ImageOps.exif_transpose(image) image = ImageOps.exif_transpose(image)
image = image.convert("RGB") image = image.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0 image = np.array(image).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,] image = torch.from_numpy(image)[None,]
return [image]
except: except:
pass
return [image] return [image]

View File

@ -53,9 +53,9 @@ function sendEventToCD(event, data) {
function sendDirectEventToCD(event, data) { function sendDirectEventToCD(event, data) {
const message = { const message = {
type: event, type: event,
data: data data: data,
} };
window.parent.postMessage(message, '*') window.parent.postMessage(message, "*");
} }
function dispatchAPIEventData(data) { function dispatchAPIEventData(data) {
@ -494,6 +494,13 @@ const ext = {
return r; return r;
}; };
if (
nodeData?.input?.optional?.default_value_url?.[1]?.image_preview === true
) {
nodeData.input.optional.default_value_url = ["IMAGEPREVIEW"];
console.log(nodeData.input.optional.default_value_url);
}
// const origonNodeCreated = nodeType.prototype.onNodeCreated; // const origonNodeCreated = nodeType.prototype.onNodeCreated;
// nodeType.prototype.onNodeCreated = function () { // nodeType.prototype.onNodeCreated = function () {
// const r = origonNodeCreated // const r = origonNodeCreated
@ -620,6 +627,78 @@ const ext = {
ComfyDeploy.category = "deploy"; ComfyDeploy.category = "deploy";
}, },
getCustomWidgets() {
return {
IMAGEPREVIEW(node, inputName, inputData) {
// Find or create the URL input widget
const urlWidget = node.addWidget(
"string",
inputName,
/* value=*/ "",
() => {},
{ serialize: true },
);
const buttonWidget = node.addWidget(
"button",
"Open Assets Browser",
/* value=*/ "",
() => {
sendEventToCD("assets", {
node: node.id,
inputName: inputName,
})
// console.log("load image");
},
{ serialize: false },
);
console.log(node.widgets);
console.log("urlWidget", urlWidget);
// Add image preview functionality
function showImage(url) {
const img = new Image();
img.onload = () => {
node.imgs = [img];
app.graph.setDirtyCanvas(true);
node.setSizeForImage?.();
};
img.onerror = () => {
node.imgs = [];
app.graph.setDirtyCanvas(true);
};
img.src = url;
}
// Set up URL widget value handling
let default_value = urlWidget.value;
Object.defineProperty(urlWidget, "value", {
set: function (value) {
this._real_value = value;
// Preview image when URL changes
if (value) {
showImage(value);
}
},
get: function () {
return this._real_value || default_value;
},
});
// Show initial image if URL exists
requestAnimationFrame(() => {
if (urlWidget.value) {
showImage(urlWidget.value);
}
});
return { widget: urlWidget };
},
};
},
async setup() { async setup() {
// const graphCanvas = document.getElementById("graph-canvas"); // const graphCanvas = document.getElementById("graph-canvas");
@ -661,8 +740,8 @@ const ext = {
console.warn("api.handlePromptGenerated is not a function"); console.warn("api.handlePromptGenerated is not a function");
} }
sendEventToCD("cd_plugin_onQueuePrompt", prompt); sendEventToCD("cd_plugin_onQueuePrompt", prompt);
} else if (message.type === 'configure_queue_buttons') { } else if (message.type === "configure_queue_buttons") {
addQueueButtons(message.data) addQueueButtons(message.data);
} else if (message.type === "get_prompt") { } else if (message.type === "get_prompt") {
const prompt = await app.graphToPrompt(); const prompt = await app.graphToPrompt();
sendEventToCD("cd_plugin_onGetPrompt", prompt); sendEventToCD("cd_plugin_onGetPrompt", prompt);
@ -1903,117 +1982,118 @@ api.fetchApi = async (route, options) => {
return await orginal_fetch_api.call(api, route, options); return await orginal_fetch_api.call(api, route, options);
}; };
// Intercept window drag and drop events // Intercept window drag and drop events
const originalDropHandler = document.ondrop const originalDropHandler = document.ondrop;
document.ondrop = async (e) => { document.ondrop = async (e) => {
console.log('Drop event intercepted:', e) console.log("Drop event intercepted:", e);
// Prevent default browser behavior // Prevent default browser behavior
e.preventDefault() e.preventDefault();
// Handle files if present // Handle files if present
if (e.dataTransfer?.files?.length > 0) { if (e.dataTransfer?.files?.length > 0) {
const files = Array.from(e.dataTransfer.files) const files = Array.from(e.dataTransfer.files);
// Send file data to parent directly as JSON // Send file data to parent directly as JSON
sendDirectEventToCD('file_drop', { sendDirectEventToCD("file_drop", {
files: files, files: files,
x: e.clientX, x: e.clientX,
y: e.clientY, y: e.clientY,
timestamp: Date.now() timestamp: Date.now(),
}) });
} }
// Call original handler if exists // Call original handler if exists
if (originalDropHandler) { if (originalDropHandler) {
originalDropHandler(e) originalDropHandler(e);
} }
} };
const originalDragEnterHandler = document.ondragenter const originalDragEnterHandler = document.ondragenter;
document.ondragenter = (e) => { document.ondragenter = (e) => {
// Prevent default to allow drop // Prevent default to allow drop
e.preventDefault() e.preventDefault();
// Send dragenter event to parent directly as JSON // Send dragenter event to parent directly as JSON
sendDirectEventToCD('file_dragenter', { sendDirectEventToCD("file_dragenter", {
x: e.clientX, x: e.clientX,
y: e.clientY, y: e.clientY,
timestamp: Date.now() timestamp: Date.now(),
}) });
if (originalDragEnterHandler) { if (originalDragEnterHandler) {
originalDragEnterHandler(e) originalDragEnterHandler(e);
} }
} };
const originalDragLeaveHandler = document.ondragleave const originalDragLeaveHandler = document.ondragleave;
document.ondragleave = (e) => { document.ondragleave = (e) => {
// Prevent default to allow drop // Prevent default to allow drop
e.preventDefault() e.preventDefault();
// Send dragleave event to parent directly as JSON // Send dragleave event to parent directly as JSON
sendDirectEventToCD('file_dragleave', { sendDirectEventToCD("file_dragleave", {
x: e.clientX, x: e.clientX,
y: e.clientY, y: e.clientY,
timestamp: Date.now() timestamp: Date.now(),
}) });
if (originalDragLeaveHandler) { if (originalDragLeaveHandler) {
originalDragLeaveHandler(e) originalDragLeaveHandler(e);
} }
} };
const originalDragOverHandler = document.ondragover const originalDragOverHandler = document.ondragover;
document.ondragover = (e) => { document.ondragover = (e) => {
// Prevent default to allow drop // Prevent default to allow drop
e.preventDefault() e.preventDefault();
// Send dragover event to parent directly as JSON // Send dragover event to parent directly as JSON
sendDirectEventToCD('file_dragover', { sendDirectEventToCD("file_dragover", {
x: e.clientX, x: e.clientX,
y: e.clientY, y: e.clientY,
timestamp: Date.now() timestamp: Date.now(),
}) });
if (originalDragOverHandler) { if (originalDragOverHandler) {
originalDragOverHandler(e) originalDragOverHandler(e);
} }
} };
// Function to create a single button // Function to create a single button
function createQueueButton(config) { function createQueueButton(config) {
const button = document.createElement('button') const button = document.createElement("button");
button.id = `cd-button-${config.id}` button.id = `cd-button-${config.id}`;
button.className = 'p-button p-component p-button-icon-only p-button-secondary p-button-text' button.className =
"p-button p-component p-button-icon-only p-button-secondary p-button-text";
button.innerHTML = ` button.innerHTML = `
<span class="p-button-icon pi ${config.icon}"></span> <span class="p-button-icon pi ${config.icon}"></span>
<span class="p-button-label">&nbsp;</span> <span class="p-button-label">&nbsp;</span>
` `;
button.onclick = () => { button.onclick = () => {
const eventData = typeof config.eventData === 'function' ? const eventData =
config.eventData() : typeof config.eventData === "function"
config.eventData || {} ? config.eventData()
sendEventToCD(config.event, eventData) : config.eventData || {};
} sendEventToCD(config.event, eventData);
button.setAttribute('data-pd-tooltip', config.tooltip) };
return button button.setAttribute("data-pd-tooltip", config.tooltip);
return button;
} }
// Function to add buttons to queue group // Function to add buttons to queue group
function addQueueButtons(buttonConfigs = DEFAULT_BUTTONS) { function addQueueButtons(buttonConfigs = DEFAULT_BUTTONS) {
const queueButtonGroup = document.querySelector('.queue-button-group.flex') const queueButtonGroup = document.querySelector(".queue-button-group.flex");
if (!queueButtonGroup) return if (!queueButtonGroup) return;
// Remove any existing CD buttons // Remove any existing CD buttons
const existingButtons = queueButtonGroup.querySelectorAll('[id^="cd-button-"]') const existingButtons =
existingButtons.forEach(button => button.remove()) queueButtonGroup.querySelectorAll('[id^="cd-button-"]');
existingButtons.forEach((button) => button.remove());
// Add new buttons // Add new buttons
buttonConfigs.forEach(config => { buttonConfigs.forEach((config) => {
const button = createQueueButton(config) const button = createQueueButton(config);
queueButtonGroup.appendChild(button) queueButtonGroup.appendChild(button);
}) });
} }