From 2a3e4d528880cadd95e756bd8a877a0642f08c8a Mon Sep 17 00:00:00 2001 From: nofunstudio Date: Sat, 1 Feb 2025 15:28:56 -0700 Subject: [PATCH] added iframe 3d viewer --- __init__.py | 10 +- __pycache__/__init__.cpython-312.pyc | Bin 0 -> 738 bytes __pycache__/iframe_view.cpython-312.pyc | Bin 0 -> 7770 bytes .../layered_infinite_zoom.cpython-312.pyc | Bin 0 -> 6790 bytes .../replicate_Flux_Fill.cpython-312.pyc | Bin 0 -> 11014 bytes .../replicate_Flux_Pro_Ultra.cpython-312.pyc | Bin 0 -> 12472 bytes iframe_view.py | 165 ++++++++++ js/iframe_view.js | 296 ++++++++++++++++++ 8 files changed, 469 insertions(+), 2 deletions(-) create mode 100644 __pycache__/__init__.cpython-312.pyc create mode 100644 __pycache__/iframe_view.cpython-312.pyc create mode 100644 __pycache__/layered_infinite_zoom.cpython-312.pyc create mode 100644 __pycache__/replicate_Flux_Fill.cpython-312.pyc create mode 100644 __pycache__/replicate_Flux_Pro_Ultra.cpython-312.pyc create mode 100644 iframe_view.py create mode 100644 js/iframe_view.js diff --git a/__init__.py b/__init__.py index dabfaab..c3cb656 100644 --- a/__init__.py +++ b/__init__.py @@ -2,19 +2,25 @@ from .layered_infinite_zoom import LayeredInfiniteZoom from .replicate_Flux_Pro_Ultra import ReplicateAPI_flux_1_1_pro_ultra from .replicate_Flux_Fill import ReplicateAPI_flux_fill_pro +from .iframe_view import IframeView + +WEB_DIRECTORY = "./js" NODE_CLASS_MAPPINGS = { "LayeredInfiniteZoom": LayeredInfiniteZoom, "ReplicateAPI_flux_1_1_pro_ultra": ReplicateAPI_flux_1_1_pro_ultra, - "ReplicateAPI_flux_fill_pro": ReplicateAPI_flux_fill_pro + "ReplicateAPI_flux_fill_pro": ReplicateAPI_flux_fill_pro, + "IframeView": IframeView } NODE_DISPLAY_NAME_MAPPINGS = { "LayeredInfiniteZoom": "Layered Infinite Zoom", "ReplicateAPI_flux_1_1_pro_ultra": "Replicate flux 1.1 pro ultra", - "ReplicateAPI_flux_fill_pro": "Replicate flux fill pro" + "ReplicateAPI_flux_fill_pro": "Replicate flux fill pro", + "IframeView": "Iframe View" } __all__ = [ "NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", + "WEB_DIRECTORY" ] diff --git a/__pycache__/__init__.cpython-312.pyc b/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03eebb99b13ae1c6025183d66e70351eff1f7ee5 GIT binary patch literal 738 zcmZWnO=}ZT6n&GK$>gIcC81VAutQyxY%&DFO^XndiHxLaXpGW9c!a)}GUdHYc$27^ zmHrABek|PiTim!D1_FY(a2M^aEAN{o3iSSP{<*8?>>Ayf2<<(T_)?N zufXMV0B;dNL}7?4uA)esVkxe=YJyd!aoyDutg$pVTm!J~W~f3{s#Alc-)nA`7$ifo zB$s5lb42o=6gNNLs1|-IKv7lVQfD})f)Zyu^2Xkjy1vh$yn8|?%sU%SX`|=h5u3fj zb@(R2$1^q+Ll`OlKQi(dlQYoGIU_OT^r=T*hFZ|NH zQbAbxyWEuIX1!K7VX>KzhdVdAl2^9F{57j7X{%~n>K?aj-0U>^eSFmD^_=dbeq2t9 zEvMh>G){51ab*AN6`t7-amzWen@^5UPP^5Oc$;1OgT0kOI0SvkDe-NwHVL<-Lp^Y3 zAl*rhj7vA#ZBUt99_PKp9Q*=gCN_wyG{lf010gmr9)gwlGrEKnUD?(kpdzp?z|tV_ zIQPea)%5vjK5(qFSupiE9{Yp_Ru>{}&&GJ&#h~1qVqBZduQG?+Co@JLh$3v2e?Z_s zSgMMm{6O~?$X=j>1-kof>(=YSGL0%$wBL^Q4x?h_S61IieMP0^CaTWv|`VA~%kC)%C> literal 0 HcmV?d00001 diff --git a/__pycache__/iframe_view.cpython-312.pyc b/__pycache__/iframe_view.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86428959581a9fde8b69f4eeb84b832d956b3b8b GIT binary patch literal 7770 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 WpM`om)We`wduQ3&`4=WtMgI$Pkf(S6 literal 0 HcmV?d00001 diff --git a/__pycache__/replicate_Flux_Fill.cpython-312.pyc b/__pycache__/replicate_Flux_Fill.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ee81f81dd78baa6a5791c23698ec1155b5d28f5 GIT binary patch literal 11014 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 {LIGHT_YELLOW}{nodesNames} {BLUE}{CLEAR}") + +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"] diff --git a/js/iframe_view.js b/js/iframe_view.js new file mode 100644 index 0000000..ef6ad2f --- /dev/null +++ b/js/iframe_view.js @@ -0,0 +1,296 @@ +// iframe_widget.js +import { app } from "../../scripts/app.js"; +import { $el } from "../../scripts/ui.js"; + +// Global store for texture data, keyed by unique_id +window.TEXTURE_STORE = window.TEXTURE_STORE || {}; + +// Function to create the iframe widget +async function widgetIframe(node, nodeData, inputData, app) { + // Create iframe wrapper with some styling + const iframeWrapper = $el("div.iframeWrapper", { + style: { + width: "100%", + height: "100%", + overflow: "hidden", + border: "1px solid var(--border-color)", + borderRadius: "4px" + } + }); + + // Create the iframe element + const iframe = $el("iframe", { + style: { + width: "100%", + height: "100%", + border: "none" + }, + sandbox: "allow-scripts allow-same-origin allow-forms", + loading: "lazy" + }); + + iframeWrapper.appendChild(iframe); + + // Locate our parameter widgets + const urlWidget = node.widgets.find((w) => w.name === "url"); + const widthWidget = node.widgets.find((w) => w.name === "width"); + const heightWidget = node.widgets.find((w) => w.name === "height"); + const stateWidget = node.widgets.find((w) => w.name === "scene_state"); + + // Set initial URL if provided + if (urlWidget.value) { + iframe.src = urlWidget.value; + } + + // Message handler for communication from the iframe + function messageHandler(event) { + // Ensure the message comes from our iframe + if (event.source !== iframe.contentWindow) return; + + console.log("[messageHandler] Received message:", event.data); + + const { type, data } = event.data; + switch (type) { + case 'IFRAME_READY': + sendParamsToIframe(); + break; + case 'TEXTURE_OUTPUT': + console.log("[messageHandler] TEXTURE_OUTPUT received with data:", data); + handleTextureOutput(data); + break; + case 'SCENE_STATE_UPDATED': + if (data.state) { + stateWidget.value = JSON.stringify(data.state, null, 2); + } + break; + default: + console.warn("[messageHandler] Unhandled message type:", type); + } + } + + // Attach the message handler + window.addEventListener("message", messageHandler, false); + + // Function to send parameters (width, height, scene state) to the iframe + function sendParamsToIframe() { + let sceneState; + try { + sceneState = JSON.parse(stateWidget.value || "{}"); + } catch (e) { + console.error("Error parsing scene state, using default:", e); + sceneState = {}; + } + const params = { + type: 'PARAMS_UPDATE', + data: { + width: parseInt(widthWidget.value, 10) || 512, + height: parseInt(heightWidget.value, 10) || 512, + sceneState, + } + }; + + if (iframe.contentWindow) { + // If you know the target origin, replace '*' with that string + iframe.contentWindow.postMessage(params, '*'); + } + } + + // Function to handle texture output coming from the iframe + async function handleTextureOutput(data) { + // Make sure the node has a valid unique_id + if (!node.unique_id) { + console.warn("[handleTextureOutput] Node unique_id is not set, cannot update texture store."); + return; + } + // For each expected texture key, update the hidden widget and the global texture store. + const textureKeys = ["color", "canny", "depth", "normal"]; + textureKeys.forEach((key) => { + if (data[key]) { + node.setHiddenWidgetValue(key, { + data: data[key].data, + width: data[key].width, + height: data[key].height, + format: data[key].format, + type: data[key].type, + shape: data[key].shape + }); + } + }); + + // Optionally clear heavy data from the global store if it is no longer needed + if (node.unique_id && window.TEXTURE_STORE[node.unique_id]) { + // You can conditionally delete or nullify large arrays after processing. + delete window.TEXTURE_STORE[node.unique_id]; + } + // Delay the prompt so that the global store has updated + setTimeout(() => { + console.log("[handleTextureOutput] Final global texture store for unique_id", node.unique_id, window.TEXTURE_STORE[node.unique_id]); + app.queuePrompt(); + }, 50); + } + + // Create the DOM widget for this node and register cleanup + const widget = node.addDOMWidget("iframe", "custom_widget", iframeWrapper, { + getValue() { + return { + url: urlWidget.value, + width: widthWidget.value, + height: heightWidget.value, + scene_state: stateWidget.value + }; + }, + setValue(v) { + if (v.url) { + iframe.src = v.url; + urlWidget.value = v.url; + } + } + }); + + // Attach a reference to the iframe on the widget so we can access it later + widget.iframe = iframe; + + // Handle resizing: update both node size and iframe dimensions, then re-send params + node.onResize = function () { + const width = parseInt(widthWidget.value, 10) || 512; + const height = parseInt(heightWidget.value, 10) || 512; + node.size = [width, Math.max(height + 40, 140)]; + iframe.style.width = width + "px"; + iframe.style.height = (height - 40) + "px"; + sendParamsToIframe(); + }; + + // When the URL widget changes, update the iframe's src + urlWidget.callback = function () { + iframe.src = this.value; + }; + + // When any of the parameter widgets change, update the iframe with the new parameters + widthWidget.callback = heightWidget.callback = stateWidget.callback = function () { + sendParamsToIframe(); + }; + + // Override the default setHiddenWidgetValue to also update our global TEXTURE_STORE. + node.setHiddenWidgetValue = function (name, value) { + let widgetEntry = this.widgets.find(w => w.name === name); + if (widgetEntry) { + widgetEntry.value = value; + console.log(`[setHiddenWidgetValue] Updated widget '${name}' to:`, value); + } else { + // Create the widget if it does not exist. + widgetEntry = { name, value, isHidden: true }; + this.widgets.push(widgetEntry); + console.log(`[setHiddenWidgetValue] Created and set widget '${name}' to:`, value); + } + if (this.unique_id) { + window.TEXTURE_STORE = window.TEXTURE_STORE || {}; + window.TEXTURE_STORE[this.unique_id] = window.TEXTURE_STORE[this.unique_id] || {}; + window.TEXTURE_STORE[this.unique_id][name] = value; + console.log(`[setHiddenWidgetValue] Global texture store for unique_id '${this.unique_id}':`, window.TEXTURE_STORE[this.unique_id]); + } + }; + + // When creating the widget +node.cleanup = () => { + window.removeEventListener("message", messageHandler, false); + if (node.unique_id && window.TEXTURE_STORE[node.unique_id]) { + delete window.TEXTURE_STORE[node.unique_id]; + } + console.log("[cleanup] Cleaned up resources for node:", node.unique_id); + }; + + // Updated onSerialize: Strip out the heavy "data" field to avoid localStorage quota problems. + node.onSerialize = (nodeData) => { + const textureKeys = ["color", "canny", "depth", "normal"]; + nodeData.hidden = nodeData.hidden || {}; + textureKeys.forEach((key) => { + const widgetEntry = node.widgets.find(w => w.name === key); + if (widgetEntry && widgetEntry.value) { + // If the widget's value includes a "data" field, remove it from the serialization. + if ("data" in widgetEntry.value) { + const { data, ...metadata } = widgetEntry.value; + nodeData.hidden[key] = metadata; + } else { + nodeData.hidden[key] = widgetEntry.value; + } + } + }); + }; + + return widget; +} + +// Register the extension and add extra menu options for the IframeView node +app.registerExtension({ + name: "Iframe View", + async beforeRegisterNodeDef(nodeType, nodeData, app) { + if (nodeType.comfyClass === "IframeView") { + // Add extra menu options to refresh the iframe and trigger texture capture + nodeType.prototype.getExtraMenuOptions = function (_, options) { + options.unshift( + { + content: "🔄 Refresh Iframe", + callback: () => { + const domWidget = this.widgets.find(w => w.name === "iframe"); + if (domWidget && domWidget.iframe) { + const url = this.widgets.find(w => w.name === "url").value; + domWidget.iframe.src = url; + } + } + }, + { + content: "📸 Capture Textures", + callback: () => { + const domWidget = this.widgets.find(w => w.name === "iframe"); + if (domWidget?.iframe?.contentWindow) { + domWidget.iframe.contentWindow.postMessage( + { type: 'CAPTURE_TEXTURES' }, + '*' + ); + } + } + } + ); + }; + + const originalOnNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = async function () { + // If nodeData.hidden definitions exist, add any missing widgets. + if (nodeData && nodeData.hidden) { + Object.keys(nodeData.hidden).forEach((key) => { + if (!this.widgets.find(widget => widget.name === key)) { + this.widgets.push({ name: key, value: nodeData.hidden[key] || null, isHidden: true }); + console.log(`[onNodeCreated] Hidden widget '${key}' added.`); + } + }); + } + const r = originalOnNodeCreated ? originalOnNodeCreated.apply(this, arguments) : undefined; + const widget = await widgetIframe(this, nodeData, nodeData, app); + this.onResize(); + + // Synchronize the node's unique_id with the one passed from Python. + if (nodeData && nodeData.hidden && nodeData.hidden.unique_id) { + this.unique_id = nodeData.hidden.unique_id; + console.log(`[onNodeCreated] Using provided unique_id from nodeData: ${this.unique_id}`); + let uniqueWidget = this.widgets.find(w => w.name === "unique_id"); + if (uniqueWidget) { + uniqueWidget.value = this.unique_id; + } else { + this.widgets.push({ name: "unique_id", value: this.unique_id, isHidden: true }); + } + } else { + // Fallback: generate a unique id. + this.unique_id = Math.random().toString(36).substr(2, 9); + console.log(`[onNodeCreated] Generated fallback unique_id: ${this.unique_id}`); + let uniqueWidget = this.widgets.find(w => w.name === "unique_id"); + if (uniqueWidget) uniqueWidget.value = this.unique_id; + else this.widgets.push({ name: "unique_id", value: this.unique_id, isHidden: true }); + } + return r; + }; + } + } +}); + +export { widgetIframe }; +