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": (
"STRING",
{"multiline": True, "default": ""},
{"multiline": False, "default": ""},
),
"default_value_url": ("STRING", {"image_preview": True, "default": ""}),
}
}
@ -33,31 +34,43 @@ class ComfyUIDeployExternalImage:
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
# 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:
if input_id.startswith('http'):
if url.startswith('http'):
import requests
from io import BytesIO
print("Fetching image from url: ", input_id)
response = requests.get(input_id)
print(f"Fetching image from url: {url}")
response = requests.get(url)
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
from io import BytesIO
print("Decoding base64 image")
base64_image = input_id[input_id.find(",")+1:]
base64_image = url[url.find(",")+1:]
decoded_image = base64.b64decode(base64_image)
image = Image.open(BytesIO(decoded_image))
else:
raise ValueError("Invalid image url provided.")
break
except:
continue
if image is not None:
try:
image = ImageOps.exif_transpose(image)
image = image.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,]
return [image]
except:
pass
return [image]

View File

@ -53,9 +53,9 @@ function sendEventToCD(event, data) {
function sendDirectEventToCD(event, data) {
const message = {
type: event,
data: data
}
window.parent.postMessage(message, '*')
data: data,
};
window.parent.postMessage(message, "*");
}
function dispatchAPIEventData(data) {
@ -494,6 +494,13 @@ const ext = {
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;
// nodeType.prototype.onNodeCreated = function () {
// const r = origonNodeCreated
@ -620,6 +627,78 @@ const ext = {
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() {
// const graphCanvas = document.getElementById("graph-canvas");
@ -661,8 +740,8 @@ const ext = {
console.warn("api.handlePromptGenerated is not a function");
}
sendEventToCD("cd_plugin_onQueuePrompt", prompt);
} else if (message.type === 'configure_queue_buttons') {
addQueueButtons(message.data)
} else if (message.type === "configure_queue_buttons") {
addQueueButtons(message.data);
} else if (message.type === "get_prompt") {
const prompt = await app.graphToPrompt();
sendEventToCD("cd_plugin_onGetPrompt", prompt);
@ -1903,117 +1982,118 @@ api.fetchApi = async (route, options) => {
return await orginal_fetch_api.call(api, route, options);
};
// Intercept window drag and drop events
const originalDropHandler = document.ondrop
const originalDropHandler = document.ondrop;
document.ondrop = async (e) => {
console.log('Drop event intercepted:', e)
console.log("Drop event intercepted:", e);
// Prevent default browser behavior
e.preventDefault()
e.preventDefault();
// Handle files if present
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
sendDirectEventToCD('file_drop', {
sendDirectEventToCD("file_drop", {
files: files,
x: e.clientX,
y: e.clientY,
timestamp: Date.now()
})
timestamp: Date.now(),
});
}
// Call original handler if exists
if (originalDropHandler) {
originalDropHandler(e)
}
originalDropHandler(e);
}
};
const originalDragEnterHandler = document.ondragenter
const originalDragEnterHandler = document.ondragenter;
document.ondragenter = (e) => {
// Prevent default to allow drop
e.preventDefault()
e.preventDefault();
// Send dragenter event to parent directly as JSON
sendDirectEventToCD('file_dragenter', {
sendDirectEventToCD("file_dragenter", {
x: e.clientX,
y: e.clientY,
timestamp: Date.now()
})
timestamp: Date.now(),
});
if (originalDragEnterHandler) {
originalDragEnterHandler(e)
}
originalDragEnterHandler(e);
}
};
const originalDragLeaveHandler = document.ondragleave
const originalDragLeaveHandler = document.ondragleave;
document.ondragleave = (e) => {
// Prevent default to allow drop
e.preventDefault()
e.preventDefault();
// Send dragleave event to parent directly as JSON
sendDirectEventToCD('file_dragleave', {
sendDirectEventToCD("file_dragleave", {
x: e.clientX,
y: e.clientY,
timestamp: Date.now()
})
timestamp: Date.now(),
});
if (originalDragLeaveHandler) {
originalDragLeaveHandler(e)
}
originalDragLeaveHandler(e);
}
};
const originalDragOverHandler = document.ondragover
const originalDragOverHandler = document.ondragover;
document.ondragover = (e) => {
// Prevent default to allow drop
e.preventDefault()
e.preventDefault();
// Send dragover event to parent directly as JSON
sendDirectEventToCD('file_dragover', {
sendDirectEventToCD("file_dragover", {
x: e.clientX,
y: e.clientY,
timestamp: Date.now()
})
timestamp: Date.now(),
});
if (originalDragOverHandler) {
originalDragOverHandler(e)
}
originalDragOverHandler(e);
}
};
// Function to create a single button
function createQueueButton(config) {
const button = document.createElement('button')
button.id = `cd-button-${config.id}`
button.className = 'p-button p-component p-button-icon-only p-button-secondary p-button-text'
const button = document.createElement("button");
button.id = `cd-button-${config.id}`;
button.className =
"p-button p-component p-button-icon-only p-button-secondary p-button-text";
button.innerHTML = `
<span class="p-button-icon pi ${config.icon}"></span>
<span class="p-button-label">&nbsp;</span>
`
`;
button.onclick = () => {
const eventData = typeof config.eventData === 'function' ?
config.eventData() :
config.eventData || {}
sendEventToCD(config.event, eventData)
}
button.setAttribute('data-pd-tooltip', config.tooltip)
return button
const eventData =
typeof config.eventData === "function"
? config.eventData()
: config.eventData || {};
sendEventToCD(config.event, eventData);
};
button.setAttribute("data-pd-tooltip", config.tooltip);
return button;
}
// Function to add buttons to queue group
function addQueueButtons(buttonConfigs = DEFAULT_BUTTONS) {
const queueButtonGroup = document.querySelector('.queue-button-group.flex')
if (!queueButtonGroup) return
const queueButtonGroup = document.querySelector(".queue-button-group.flex");
if (!queueButtonGroup) return;
// Remove any existing CD buttons
const existingButtons = queueButtonGroup.querySelectorAll('[id^="cd-button-"]')
existingButtons.forEach(button => button.remove())
const existingButtons =
queueButtonGroup.querySelectorAll('[id^="cd-button-"]');
existingButtons.forEach((button) => button.remove());
// Add new buttons
buttonConfigs.forEach(config => {
const button = createQueueButton(config)
queueButtonGroup.appendChild(button)
})
buttonConfigs.forEach((config) => {
const button = createQueueButton(config);
queueButtonGroup.appendChild(button);
});
}