Files
2026-01-28 19:33:35 +13:00

133 lines
5.1 KiB
JavaScript

/**
* 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<HTMLImageElement|null>} 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);
}
}