133 lines
5.1 KiB
JavaScript
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);
|
|
}
|
|
}
|