/** * Background image drawing functions */ import { loadImageAsync } from "../utils/fileUpload.js"; import { resizeCanvasToImage } from "../components/Canvas.js"; /** * Resolve preview image from a ComfyUI node * @param {Object} targetNode - ComfyUI node * @returns {HTMLImageElement|null} Preview image or null */ export function resolveNodePreviewImage(targetNode) { if (!targetNode) return null; if (targetNode.imgs && targetNode.imgs.length > 0) return targetNode.imgs[0]; if (targetNode.images && targetNode.images.length > 0) return targetNode.images[0]; if (targetNode._bgImage) return targetNode._bgImage; return null; } /** * Get connected input node from ComfyUI graph * @param {Object} node - Current node * @param {Object} app - ComfyUI app instance * @returns {Object|null} Connected input node or null */ export function getConnectedInputNode(node, app) { const input = node.inputs && node.inputs[0]; if (!input || input.link == null) return null; const link = app.graph && app.graph.links && app.graph.links[input.link]; if (!link) return null; return app.graph.getNodeById(link.origin_id); } /** * Get preview image from connected input node * @param {Object} node - Current node * @param {Object} app - ComfyUI app instance * @returns {HTMLImageElement|null} Preview image or null */ export function getInputPreviewImage(node, app) { const inputNode = getConnectedInputNode(node, app); if (!inputNode) return null; return resolveNodePreviewImage(inputNode); } /** * Get frame image for a given index * @param {Object} state - Editor state * @param {number} index - Frame index (0-based) * @returns {Promise} Loaded image or null */ export async function getFrameImageForIndex(state, index) { if (!state.frameImages.length) return null; const safeIndex = Math.max(0, Math.min(state.frameImages.length - 1, index)); const entry = state.frameImages[safeIndex]; if (!entry) return null; if (state.frameImageCache.has(entry.url)) { return state.frameImageCache.get(entry.url); } const img = await loadImageAsync(entry.url); state.frameImageCache.set(entry.url, img); return img; } /** * Draw background image on canvas * @param {CanvasRenderingContext2D} ctx - Canvas context * @param {HTMLCanvasElement} canvas - Canvas element * @param {Object} state - Editor state * @param {Object} node - ComfyUI node * @param {Object} app - ComfyUI app instance * @param {Function} resizeCanvasToImageFn - Function to resize canvas * @param {Function} redrawFn - Function to trigger redraw */ export function drawBackgroundImage(ctx, canvas, state, node, app, resizeCanvasToImageFn, redrawFn) { try { // If user loaded frame images, use those first if (state.frameImages.length > 0) { // Convert 1-based frame number to 0-based array index const index = (state.currentFrame - 1) % state.frameImages.length; const cached = state.frameImages[index]; if (cached && state.frameImageCache.has(cached.url)) { const img = state.frameImageCache.get(cached.url); resizeCanvasToImageFn(canvas, state, img); ctx.drawImage(img, 0, 0, canvas.width, canvas.height); return; } else { // Kick off async load; will be drawn on next redraw getFrameImageForIndex(state, index).then(() => { if (redrawFn) redrawFn(); }); return; } } // Preferred: use upstream node preview image (ComfyUI uses imgs/images) const preview = getInputPreviewImage(node, app); if (preview) { // Cache preview to avoid repeated lookups if (preview !== state.previewImage) { state.previewImage = preview; } resizeCanvasToImageFn(canvas, state, state.previewImage); ctx.drawImage(state.previewImage, 0, 0, canvas.width, canvas.height); return; } // Fallback: attempt to use raw input data if available if (node && typeof node.getInputData === "function") { const input = node.getInputData(0); if (!input) return; if (input instanceof HTMLImageElement || input instanceof HTMLCanvasElement || input instanceof ImageBitmap) { ctx.drawImage(input, 0, 0, canvas.width, canvas.height); return; } if (input.data && input.width && input.height) { const imageData = new ImageData(new Uint8ClampedArray(input.data), input.width, input.height); const tempCanvas = document.createElement("canvas"); tempCanvas.width = input.width; tempCanvas.height = input.height; const tempCtx = tempCanvas.getContext("2d"); tempCtx.putImageData(imageData, 0, 0); ctx.drawImage(tempCanvas, 0, 0, canvas.width, canvas.height); } } } catch (error) { console.warn("[ComfyUI Roto] Unable to render background image:", error); } }