ref update
This commit is contained in:
@@ -32,6 +32,7 @@ from .nodes.cache_samples import *
|
||||
# Import API endpoints to register routes
|
||||
from . import api
|
||||
from .utility.rgthree_api import routes_model_info
|
||||
from .nodes import trigger_ref_refresh # Register PrepareRefs backend trigger endpoint
|
||||
|
||||
NODE_CONFIG = {}
|
||||
|
||||
|
||||
@@ -26,6 +26,17 @@ def get_bg_folder_path():
|
||||
|
||||
return str(bg_path)
|
||||
|
||||
def get_ref_folder_path():
|
||||
"""Get the path to the ref folder where reference images are stored"""
|
||||
import pathlib
|
||||
current_dir = pathlib.Path(__file__).parent
|
||||
ref_path = current_dir / "web" / "power_spline_editor" / "ref"
|
||||
|
||||
# Create the directory if it doesn't exist
|
||||
ref_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
return str(ref_path)
|
||||
|
||||
@PromptServer.instance.routes.post("/wanvideowrapper_qq/save_ref_image")
|
||||
async def save_ref_image(request):
|
||||
"""API endpoint to save ref_image to the bg folder"""
|
||||
@@ -33,15 +44,15 @@ async def save_ref_image(request):
|
||||
post = await request.post()
|
||||
image_data = post.get("image")
|
||||
image_name = post.get("name", "bg_image.png")
|
||||
|
||||
|
||||
if not image_data:
|
||||
return web.json_response({"error": "No image data provided"}, status=400)
|
||||
|
||||
|
||||
# Derive filename safely
|
||||
safe_name = os.path.basename(image_name) or "bg_image.png"
|
||||
if "." not in safe_name:
|
||||
safe_name += ".png"
|
||||
|
||||
|
||||
# Decode base64 image data
|
||||
if image_data.startswith('data:image'):
|
||||
# Remove data URL prefix (e.g., "data:image/png;base64,")
|
||||
@@ -50,10 +61,10 @@ async def save_ref_image(request):
|
||||
else:
|
||||
encoded = image_data
|
||||
image_format = safe_name.split(".")[-1]
|
||||
|
||||
|
||||
# Decode the base64 string
|
||||
image_bytes = base64.b64decode(encoded)
|
||||
|
||||
|
||||
# Verify it's a valid image
|
||||
try:
|
||||
img = Image.open(BytesIO(image_bytes))
|
||||
@@ -61,11 +72,11 @@ async def save_ref_image(request):
|
||||
img = Image.open(BytesIO(image_bytes)) # Reopen after verify
|
||||
except Exception as e:
|
||||
return web.json_response({"error": f"Invalid image data: {str(e)}"}, status=400)
|
||||
|
||||
|
||||
# Get the bg folder path
|
||||
bg_folder = get_bg_folder_path()
|
||||
ref_image_path = os.path.join(bg_folder, safe_name)
|
||||
|
||||
|
||||
# Decide format (prefer PNG to preserve alpha)
|
||||
fmt = (image_format or "png").upper()
|
||||
save_kwargs = {}
|
||||
@@ -78,9 +89,9 @@ async def save_ref_image(request):
|
||||
if img.mode not in ("RGBA", "LA"):
|
||||
img = img.convert("RGBA")
|
||||
fmt = "PNG"
|
||||
|
||||
|
||||
img.save(ref_image_path, format=fmt, **save_kwargs)
|
||||
|
||||
|
||||
return web.json_response({"success": True, "path": ref_image_path, "message": "Reference image saved successfully"})
|
||||
|
||||
except Exception as e:
|
||||
@@ -89,6 +100,86 @@ async def save_ref_image(request):
|
||||
traceback.print_exc()
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
@PromptServer.instance.routes.post("/wanvideowrapper_qq/save_prepare_refs_images")
|
||||
async def save_prepare_refs_images(request):
|
||||
"""API endpoint to save ALL images from PrepareRefs node to the REF folder"""
|
||||
try:
|
||||
data = await request.json()
|
||||
bg_image_data = data.get("bg_image")
|
||||
ref_images_data = data.get("ref_images", [])
|
||||
|
||||
print(f"[API save_prepare_refs_images] === Received request ===")
|
||||
print(f"[API save_prepare_refs_images] bg_image present: {bg_image_data is not None}")
|
||||
print(f"[API save_prepare_refs_images] ref_images count: {len(ref_images_data) if isinstance(ref_images_data, list) else 0}")
|
||||
|
||||
saved_paths = {
|
||||
"bg_image_path": None,
|
||||
"ref_images_paths": []
|
||||
}
|
||||
|
||||
# Get ref folder (ALL images go to ref folder for PrepareRefs!)
|
||||
ref_folder = get_ref_folder_path()
|
||||
print(f"[API save_prepare_refs_images] Using ref folder: {ref_folder}")
|
||||
|
||||
# Save background image to REF folder (not bg folder!)
|
||||
if bg_image_data:
|
||||
try:
|
||||
print(f"[API save_prepare_refs_images] Saving bg_image to REF folder...")
|
||||
# Decode base64 image data
|
||||
if bg_image_data.startswith('data:image'):
|
||||
header, encoded = bg_image_data.split(',', 1)
|
||||
else:
|
||||
encoded = bg_image_data
|
||||
|
||||
image_bytes = base64.b64decode(encoded)
|
||||
img = Image.open(BytesIO(image_bytes))
|
||||
|
||||
# Save to REF folder as bg_image.png
|
||||
bg_image_path = os.path.join(ref_folder, "bg_image.png")
|
||||
img.save(bg_image_path, format="PNG")
|
||||
saved_paths["bg_image_path"] = "ref/bg_image.png"
|
||||
print(f"[API save_prepare_refs_images] ✓ Saved bg_image to {bg_image_path}")
|
||||
except Exception as e:
|
||||
print(f"[API save_prepare_refs_images] ERROR saving bg_image: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# Save ref images to ref folder
|
||||
if ref_images_data and isinstance(ref_images_data, list):
|
||||
for idx, ref_image_data in enumerate(ref_images_data):
|
||||
try:
|
||||
print(f"[API save_prepare_refs_images] Saving ref_image {idx} to REF folder...")
|
||||
# Decode base64 image data
|
||||
if ref_image_data.startswith('data:image'):
|
||||
header, encoded = ref_image_data.split(',', 1)
|
||||
else:
|
||||
encoded = ref_image_data
|
||||
|
||||
image_bytes = base64.b64decode(encoded)
|
||||
img = Image.open(BytesIO(image_bytes))
|
||||
|
||||
# Save to ref folder
|
||||
ref_image_path = os.path.join(ref_folder, f"ref_image_{idx}.png")
|
||||
img.save(ref_image_path, format="PNG")
|
||||
saved_paths["ref_images_paths"].append(f"ref/ref_image_{idx}.png")
|
||||
print(f"[API save_prepare_refs_images] ✓ Saved ref_image_{idx} to {ref_image_path}")
|
||||
except Exception as e:
|
||||
print(f"[API save_prepare_refs_images] ERROR saving ref_image {idx}: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
print(f"[API save_prepare_refs_images] === COMPLETE ===")
|
||||
print(f"[API save_prepare_refs_images] Saved bg_image: {saved_paths['bg_image_path']}")
|
||||
print(f"[API save_prepare_refs_images] Saved {len(saved_paths['ref_images_paths'])} ref images")
|
||||
|
||||
return web.json_response({"success": True, "paths": saved_paths})
|
||||
|
||||
except Exception as e:
|
||||
print(f"[API save_prepare_refs_images] ERROR: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
def get_lora_full_path(lora_name):
|
||||
"""Get the full path to a LoRA file"""
|
||||
try:
|
||||
|
||||
+772
-485
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,131 @@
|
||||
from server import PromptServer
|
||||
from aiohttp import web
|
||||
import base64
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
import torch
|
||||
import numpy as np
|
||||
|
||||
# Import PrepareRefs class
|
||||
from .prepare_refs import PrepareRefs
|
||||
|
||||
|
||||
def pil_to_tensor(pil_img):
|
||||
"""Convert PIL image to tensor [1, H, W, C] in range [0, 1]"""
|
||||
img_np = np.array(pil_img).astype(np.float32) / 255.0
|
||||
if len(img_np.shape) == 2: # Grayscale
|
||||
img_np = np.stack([img_np] * 3, axis=-1)
|
||||
return torch.from_numpy(img_np)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/wanvideowrapper_qq/trigger_prepare_refs")
|
||||
async def trigger_prepare_refs(request):
|
||||
"""
|
||||
Backend trigger to run PrepareRefs processing without node execution.
|
||||
|
||||
Input JSON:
|
||||
{
|
||||
"bg_image": "data:image/png;base64,...",
|
||||
"ref_layer_data": [{name, on, lassoShape: {additivePaths}}],
|
||||
"mask_width": 640,
|
||||
"mask_height": 480
|
||||
}
|
||||
|
||||
Note: export_alpha and to_bounding_box are always True (hardcoded in PrepareRefs).
|
||||
All ref images are exported as 768x768 PNG with alpha channel.
|
||||
|
||||
Output JSON:
|
||||
{
|
||||
"success": true/false,
|
||||
"paths": {
|
||||
"bg_image_cl": "ref/bg_image_cl.png",
|
||||
"bg_preview": "bg/bg_image.png",
|
||||
"ref_images": ["ref/ref_1.png", ...],
|
||||
"ref_masks": ["ref/ref_1_mask.png", ...]
|
||||
},
|
||||
"message": "PrepareRefs processing complete: N layers processed",
|
||||
"error": "error message if failed"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = await request.json()
|
||||
|
||||
# Extract parameters
|
||||
bg_image_b64 = data.get("bg_image")
|
||||
ref_layer_data = data.get("ref_layer_data", [])
|
||||
mask_width = data.get("mask_width", 640)
|
||||
mask_height = data.get("mask_height", 480)
|
||||
|
||||
print(f"[trigger_prepare_refs] Received request with {len(ref_layer_data)} layers, dims: {mask_width}x{mask_height}")
|
||||
|
||||
# Validate layer data
|
||||
if not ref_layer_data or len(ref_layer_data) == 0:
|
||||
return web.json_response({
|
||||
"success": False,
|
||||
"error": "No ref_layer_data provided"
|
||||
}, status=400)
|
||||
|
||||
# Decode bg_image to tensor
|
||||
bg_tensor = None
|
||||
if bg_image_b64:
|
||||
# Remove data URL prefix if present
|
||||
if bg_image_b64.startswith('data:image'):
|
||||
bg_image_b64 = bg_image_b64.split(',', 1)[1]
|
||||
|
||||
image_bytes = base64.b64decode(bg_image_b64)
|
||||
pil_img = Image.open(BytesIO(image_bytes))
|
||||
|
||||
# Convert to RGB if needed
|
||||
if pil_img.mode != 'RGB':
|
||||
pil_img = pil_img.convert('RGB')
|
||||
|
||||
print(f"[trigger_prepare_refs] Decoded bg_image: {pil_img.size}, mode: {pil_img.mode}")
|
||||
|
||||
# Convert to tensor [1, H, W, C]
|
||||
bg_tensor = pil_to_tensor(pil_img).unsqueeze(0)
|
||||
|
||||
# Construct prompt structure (PrepareRefs expects this format)
|
||||
prompt = {
|
||||
"unique_id": {
|
||||
"inputs": {
|
||||
"ref_layer_data": ref_layer_data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create PrepareRefs instance and execute
|
||||
print(f"[trigger_prepare_refs] Calling PrepareRefs.prepare()...")
|
||||
prep_refs = PrepareRefs()
|
||||
result = prep_refs.prepare(
|
||||
mask_width=mask_width,
|
||||
mask_height=mask_height,
|
||||
bg_image=bg_tensor,
|
||||
unique_id="unique_id", # Key used in prompt dict
|
||||
prompt=prompt
|
||||
)
|
||||
|
||||
# Extract paths from result
|
||||
ui_data = result.get("ui", {})
|
||||
paths = {
|
||||
"bg_image_cl": ui_data.get("bg_image_path", [None])[0],
|
||||
"bg_preview": ui_data.get("bg_image_preview_path", [None])[0],
|
||||
"ref_images": ui_data.get("ref_images_paths", []),
|
||||
"ref_masks": ui_data.get("ref_masks_paths", [])
|
||||
}
|
||||
|
||||
print(f"[trigger_prepare_refs] Processing complete. Generated paths: {paths}")
|
||||
|
||||
return web.json_response({
|
||||
"success": True,
|
||||
"paths": paths,
|
||||
"message": f"PrepareRefs processing complete: {len(ref_layer_data)} layers processed"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"[trigger_prepare_refs] ERROR: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return web.json_response({
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}, status=500)
|
||||
@@ -494,6 +494,9 @@ function enterLassoMode(node, refLayer) {
|
||||
canvas.style.cursor = 'crosshair';
|
||||
}
|
||||
|
||||
// Update button states to show green pen for active layer
|
||||
node.updateLayerButtonStates?.();
|
||||
|
||||
console.log(`Lasso mode activated for ${refLayer.value.name}`);
|
||||
}
|
||||
|
||||
@@ -518,6 +521,9 @@ function exitLassoMode(node) {
|
||||
canvas.style.cursor = 'default';
|
||||
}
|
||||
|
||||
// Update button states to reset pen colors
|
||||
node.updateLayerButtonStates?.();
|
||||
|
||||
console.log('Lasso mode deactivated');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
drawNumberWidgetPart,
|
||||
RgthreeBaseWidget
|
||||
} from './drawing_utils.js';
|
||||
import { triggerPrepareRefsBackend } from './trigger_ref_refresh.js';
|
||||
|
||||
// === TOP ROW WIDGET (Combined refresh button, bg_image dropdown, and width/height controls) ===
|
||||
export class TopRowWidget extends RgthreeBaseWidget {
|
||||
@@ -268,28 +269,65 @@ export class TopRowWidget extends RgthreeBaseWidget {
|
||||
// Set up event handlers for refresh button
|
||||
if (this.visibility.refreshCanvasButton) {
|
||||
this.hitAreas.refreshCanvasButton.onClick = async () => {
|
||||
// Update all box layer ref images from connected ref_images
|
||||
if (node.updateAllBoxLayerRefs) {
|
||||
try {
|
||||
await node.updateAllBoxLayerRefs();
|
||||
} catch (e) {
|
||||
console.warn('Failed to update box layer refs:', e);
|
||||
// Check if ref_images input is connected to PrepareRefs
|
||||
let isPrepareRefsConnected = false;
|
||||
let prepareRefsNode = null;
|
||||
try {
|
||||
// Import the graph query function at the top of the file
|
||||
const { findConnectedSourceNode } = await import('./graph_query.js');
|
||||
const sourceNodeObj = findConnectedSourceNode(node, 'ref_images');
|
||||
if (sourceNodeObj && sourceNodeObj.node) {
|
||||
if (sourceNodeObj.node.type === 'PrepareRefs') {
|
||||
console.log('[Refresh] PowerSplineEditor connected to PrepareRefs');
|
||||
isPrepareRefsConnected = true;
|
||||
prepareRefsNode = sourceNodeObj.node;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to check ref_images connection:', e);
|
||||
}
|
||||
|
||||
// Wait for reference image update and scale recalculation to complete
|
||||
if (node.updateReferenceImageFromConnectedNode) {
|
||||
try {
|
||||
// This now properly awaits the image loading and scale recalculation
|
||||
await node.updateReferenceImageFromConnectedNode();
|
||||
if (isPrepareRefsConnected && prepareRefsNode) {
|
||||
// Trigger backend PrepareRefs processing
|
||||
console.log('[Refresh] Triggering backend PrepareRefs processing...');
|
||||
const result = await triggerPrepareRefsBackend(prepareRefsNode);
|
||||
|
||||
// Force a final render with the correct scale
|
||||
// The scale should already be correct from handleImageLoad -> recenterBackgroundImage
|
||||
if (node.editor && node.editor.layerRenderer) {
|
||||
node.editor.layerRenderer.render();
|
||||
if (result.success) {
|
||||
console.log('[Refresh] Backend processing complete, loading results...');
|
||||
|
||||
// Load the newly generated images from ref folder
|
||||
await this.loadImagesFromRefFolder(node);
|
||||
|
||||
console.log('[Refresh] Canvas refresh complete');
|
||||
} else {
|
||||
// Silent error handling - log only, no user interruption
|
||||
console.error('[Refresh] Backend processing failed:', result.error);
|
||||
}
|
||||
} else {
|
||||
// Original behavior: fetch from connected nodes
|
||||
// Update all box layer ref images from connected ref_images
|
||||
if (node.updateAllBoxLayerRefs) {
|
||||
try {
|
||||
await node.updateAllBoxLayerRefs();
|
||||
} catch (e) {
|
||||
console.warn('Failed to update box layer refs:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for reference image update and scale recalculation to complete
|
||||
if (node.updateReferenceImageFromConnectedNode) {
|
||||
try {
|
||||
// This now properly awaits the image loading and scale recalculation
|
||||
await node.updateReferenceImageFromConnectedNode();
|
||||
|
||||
// Force a final render with the correct scale
|
||||
// The scale should already be correct from handleImageLoad -> recenterBackgroundImage
|
||||
if (node.editor && node.editor.layerRenderer) {
|
||||
node.editor.layerRenderer.render();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to update reference image:', e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to update reference image:', e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,6 +473,155 @@ export class TopRowWidget extends RgthreeBaseWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// Load images from ref folder when PrepareRefs is connected
|
||||
async loadImagesFromRefFolder(node) {
|
||||
const { loadImageAsBase64 } = await import('./graph_query.js');
|
||||
const timestamp = Date.now();
|
||||
|
||||
// 1. Load bg_image_cl.png from ref folder
|
||||
try {
|
||||
const bgImageUrl = new URL(`ref/bg_image_cl.png?t=${timestamp}`, import.meta.url).href;
|
||||
const bgImageData = await loadImageAsBase64(bgImageUrl);
|
||||
|
||||
if (bgImageData) {
|
||||
// Store the background image
|
||||
node.originalRefImageData = {
|
||||
name: 'bg_image_cl.png',
|
||||
base64: bgImageData.split(',')[1],
|
||||
type: 'image/png'
|
||||
};
|
||||
|
||||
// Update background image display based on current bg_img selection
|
||||
const bgImgWidget = node.widgets?.find(w => w.name === "bg_img");
|
||||
const bg_img = bgImgWidget ? bgImgWidget.value : "None";
|
||||
await node.updateBackgroundImage(bg_img);
|
||||
|
||||
console.log('Successfully loaded bg_image_cl.png from ref folder');
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to load bg_image_cl.png from ref folder:', e);
|
||||
}
|
||||
|
||||
// 2. Find and load all ref_*.png files from ref folder
|
||||
const refImages = [];
|
||||
const maxRefs = 5; // Try to load up to 5 reference images
|
||||
|
||||
for (let i = 1; i <= maxRefs; i++) {
|
||||
try {
|
||||
const refImageUrl = new URL(`ref/ref_${i}.png?t=${timestamp}`, import.meta.url).href;
|
||||
const refImageData = await loadImageAsBase64(refImageUrl);
|
||||
|
||||
if (refImageData) {
|
||||
refImages.push(refImageData);
|
||||
console.log(`Successfully loaded ref_${i}.png from ref folder`);
|
||||
} else {
|
||||
// Stop trying if we can't load this image
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
// Stop trying if we encounter an error (file doesn't exist)
|
||||
console.log(`No more ref images found after ref_${i - 1}.png`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Update box layer refs with loaded images
|
||||
if (refImages.length > 0) {
|
||||
const activeWidget = node.layerManager?.getActiveWidget?.();
|
||||
if (!activeWidget || activeWidget.value?.type !== 'box_layer') {
|
||||
console.log('No active box layer to attach ref images');
|
||||
// Try to update all box layers instead
|
||||
await this.updateAllBoxLayersFromRefFolder(node, refImages);
|
||||
} else {
|
||||
// Update active box layer
|
||||
await this.updateBoxLayerWithRefImages(node, activeWidget, refImages);
|
||||
}
|
||||
}
|
||||
|
||||
// Force a final render
|
||||
if (node.editor && node.editor.layerRenderer) {
|
||||
node.editor.layerRenderer.render();
|
||||
}
|
||||
}
|
||||
|
||||
// Update a specific box layer with ref images from folder
|
||||
async updateBoxLayerWithRefImages(node, boxWidget, refImages) {
|
||||
const attachments = [];
|
||||
|
||||
for (let i = 0; i < refImages.length; i++) {
|
||||
const imgData = refImages[i];
|
||||
const base64Data = imgData.startsWith('data:')
|
||||
? imgData.split(',')[1]
|
||||
: imgData;
|
||||
const dataUrl = imgData.startsWith('data:')
|
||||
? imgData
|
||||
: `data:image/png;base64,${base64Data}`;
|
||||
|
||||
// Load dimensions
|
||||
const dims = await new Promise((resolve) => {
|
||||
const img = new Image();
|
||||
img.onload = () => resolve({ width: img.width, height: img.height });
|
||||
img.onerror = () => resolve({ width: 1, height: 1 });
|
||||
img.src = dataUrl;
|
||||
});
|
||||
|
||||
const filename = `ref_${i + 1}.png`;
|
||||
attachments.push({
|
||||
path: `ref/${filename}`,
|
||||
type: 'image/png',
|
||||
width: dims.width,
|
||||
height: dims.height,
|
||||
name: filename
|
||||
});
|
||||
}
|
||||
|
||||
boxWidget.value.ref_attachment = { entries: attachments };
|
||||
|
||||
// Preserve existing ref_selection if valid, otherwise default to first ref
|
||||
const currentSelection = boxWidget.value.ref_selection;
|
||||
if (attachments.length > 0) {
|
||||
// Check if current selection is still valid
|
||||
if (currentSelection && currentSelection !== 'no_ref') {
|
||||
const refIndex = parseInt(currentSelection.split('_')[1], 10);
|
||||
if (refIndex > 0 && refIndex <= attachments.length) {
|
||||
// Keep the current selection as it's still valid
|
||||
boxWidget.value.ref_selection = currentSelection;
|
||||
} else {
|
||||
// Current selection is out of range, default to ref_1
|
||||
boxWidget.value.ref_selection = 'ref_1';
|
||||
}
|
||||
} else {
|
||||
// No current selection or it was 'no_ref', default to ref_1
|
||||
boxWidget.value.ref_selection = 'ref_1';
|
||||
}
|
||||
} else {
|
||||
boxWidget.value.ref_selection = 'no_ref';
|
||||
}
|
||||
|
||||
// Clear ref image cache to force reload
|
||||
if (node.editor?.layerRenderer?.clearRefImageCache) {
|
||||
node.editor.layerRenderer.clearRefImageCache();
|
||||
}
|
||||
|
||||
node.setDirtyCanvas(true, true);
|
||||
}
|
||||
|
||||
// Update all box layers with ref images from folder
|
||||
async updateAllBoxLayersFromRefFolder(node, refImages) {
|
||||
const widgets = node.layerManager?.getSplineWidgets?.() || [];
|
||||
const boxWidgets = widgets.filter(w => w?.value?.type === 'box_layer');
|
||||
|
||||
if (!boxWidgets.length) {
|
||||
console.log('No box layers found to update');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const boxWidget of boxWidgets) {
|
||||
await this.updateBoxLayerWithRefImages(node, boxWidget, refImages);
|
||||
}
|
||||
|
||||
console.log(`Updated ${boxWidgets.length} box layer(s) with ref images from folder`);
|
||||
}
|
||||
|
||||
// Mouse event handlers
|
||||
mouse(event, pos, node) {
|
||||
|
||||
@@ -483,21 +483,92 @@ app.registerExtension({
|
||||
const bgImgWidget = this.widgets && this.widgets.find(w => w.name === "bg_img");
|
||||
const bg_img = bgImgWidget ? bgImgWidget.value : "None";
|
||||
|
||||
// Try to pull a fresh ref image from connected node silently
|
||||
const base64Image = await getReferenceImageFromConnectedNode(this);
|
||||
if (base64Image) {
|
||||
this.originalRefImageData = {
|
||||
name: 'ref_image_from_connection.jpg',
|
||||
base64: base64Image.split(',')[1],
|
||||
type: 'image/jpeg'
|
||||
};
|
||||
try { await saveRefImageToCache(this.originalRefImageData.base64, 'bg_image.png'); } catch {}
|
||||
if (this.uuid) {
|
||||
sessionStorage.removeItem(`spline-editor-img-${this.uuid}`);
|
||||
// Check if connected to PrepareRefs - if so, load bg_image_cl.png from ref folder instead
|
||||
const isConnectedToPrepareRefs = this.checkIfConnectedToPrepareRefs();
|
||||
|
||||
if (isConnectedToPrepareRefs) {
|
||||
console.log('Connected to PrepareRefs, loading bg_image_cl.png from ref folder');
|
||||
try {
|
||||
const timestamp = Date.now();
|
||||
const refImageUrl = new URL(`ref/bg_image_cl.png?t=${timestamp}`, import.meta.url).href;
|
||||
const response = await fetch(refImageUrl);
|
||||
if (response.ok) {
|
||||
const blob = await response.blob();
|
||||
const base64Data = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result.split(',')[1]);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
|
||||
this.originalRefImageData = {
|
||||
name: 'bg_image_cl.png',
|
||||
base64: base64Data,
|
||||
type: 'image/png'
|
||||
};
|
||||
|
||||
// Process the image immediately based on bg_img selection
|
||||
if (bg_img === "None") {
|
||||
// Apply darkening for "None" selection
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
const darkenedDataUrl = canvas.toDataURL('image/png');
|
||||
this.imgData = {
|
||||
name: 'bg_image_cl.png',
|
||||
base64: darkenedDataUrl.split(',')[1],
|
||||
type: 'image/png'
|
||||
};
|
||||
if (this.editor) {
|
||||
this.editor.refreshBackgroundImage();
|
||||
}
|
||||
};
|
||||
img.src = `data:image/png;base64,${base64Data}`;
|
||||
} else {
|
||||
// For A/B/C selections, set imgData directly for now
|
||||
this.imgData = {
|
||||
name: 'bg_image_cl.png',
|
||||
base64: base64Data,
|
||||
type: 'image/png'
|
||||
};
|
||||
if (this.editor) {
|
||||
this.editor.refreshBackgroundImage();
|
||||
}
|
||||
// Also trigger updateBackgroundImage for proper overlay handling
|
||||
this.updateBackgroundImage(bg_img);
|
||||
}
|
||||
|
||||
if (this.uuid) {
|
||||
sessionStorage.removeItem(`spline-editor-img-${this.uuid}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load bg_image_cl.png from ref folder:', e);
|
||||
}
|
||||
} else {
|
||||
// Try to pull a fresh ref image from connected node silently
|
||||
const base64Image = await getReferenceImageFromConnectedNode(this);
|
||||
if (base64Image) {
|
||||
this.originalRefImageData = {
|
||||
name: 'ref_image_from_connection.jpg',
|
||||
base64: base64Image.split(',')[1],
|
||||
type: 'image/jpeg'
|
||||
};
|
||||
try { await saveRefImageToCache(this.originalRefImageData.base64, 'bg_image.png'); } catch {}
|
||||
if (this.uuid) {
|
||||
sessionStorage.removeItem(`spline-editor-img-${this.uuid}`);
|
||||
}
|
||||
this.updateBackgroundImage(bg_img);
|
||||
this.editor?.refreshBackgroundImage?.();
|
||||
return;
|
||||
}
|
||||
this.updateBackgroundImage(bg_img);
|
||||
this.editor?.refreshBackgroundImage?.();
|
||||
return;
|
||||
}
|
||||
} catch {}
|
||||
// Fallback: just apply current selection to force overlay/cached handling
|
||||
@@ -617,6 +688,35 @@ app.registerExtension({
|
||||
// Set initial node size
|
||||
this.updateNodeHeight();
|
||||
|
||||
// Helper method to load the correct cached ref image based on PrepareRefs connection
|
||||
this.loadCorrectCachedRefImage = async function() {
|
||||
const isConnectedToPrepareRefs = this.checkIfConnectedToPrepareRefs();
|
||||
|
||||
if (isConnectedToPrepareRefs) {
|
||||
// Load bg_image_cl.png from ref folder
|
||||
try {
|
||||
const timestamp = Date.now();
|
||||
const refImageUrl = new URL(`ref/bg_image_cl.png?t=${timestamp}`, import.meta.url).href;
|
||||
const response = await fetch(refImageUrl);
|
||||
if (response.ok) {
|
||||
const blob = await response.blob();
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load bg_image_cl.png from ref folder:', e);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
// Load bg_image.png from bg folder (standard behavior)
|
||||
return await loadCachedRefImageAsBase64();
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
// Add method to update background image immediately based on bg_img selection
|
||||
this.updateBackgroundImage = async function(bg_img) {
|
||||
// First check if we have saved dimensions to maintain proportions
|
||||
@@ -661,7 +761,7 @@ app.registerExtension({
|
||||
};
|
||||
img.onerror = () => {
|
||||
// Fallback: try to load cached bg_image first, then default A.jpg
|
||||
loadCachedRefImageAsBase64().then(cachedImageUrl => {
|
||||
this.loadCorrectCachedRefImage().then(cachedImageUrl => {
|
||||
if (cachedImageUrl) {
|
||||
const fallbackImg = new Image();
|
||||
fallbackImg.onload = () => {
|
||||
@@ -717,7 +817,7 @@ app.registerExtension({
|
||||
img.src = `data:image/jpeg;base64,${this.originalRefImageData.base64}`;
|
||||
} else {
|
||||
// If no original ref image data, try to load cached bg_image first, then fallback to default
|
||||
loadCachedRefImageAsBase64().then(cachedImageUrl => {
|
||||
this.loadCorrectCachedRefImage().then(cachedImageUrl => {
|
||||
if (cachedImageUrl) {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
@@ -781,10 +881,11 @@ app.registerExtension({
|
||||
|
||||
if (this.originalRefImageData && this.originalRefImageData.base64) {
|
||||
// Use original ref image if available (from refresh button)
|
||||
refImageForOverlay = `data:image/jpeg;base64,${this.originalRefImageData.base64}`;
|
||||
const imgType = this.originalRefImageData.type || 'image/jpeg';
|
||||
refImageForOverlay = `data:${imgType};base64,${this.originalRefImageData.base64}`;
|
||||
} else {
|
||||
// Otherwise, load from cached
|
||||
loadCachedRefImageAsBase64().then(cachedImageUrl => {
|
||||
this.loadCorrectCachedRefImage().then(cachedImageUrl => {
|
||||
if (cachedImageUrl) {
|
||||
// Create a properly scaled overlay using the original cached ref image
|
||||
this.createScaledImageOverlay(cachedImageUrl, bg_img, imageUrl);
|
||||
@@ -815,6 +916,58 @@ app.registerExtension({
|
||||
console.log('Attempting to update reference image from connected node...');
|
||||
|
||||
try {
|
||||
// Check if we're connected to PrepareRefs node
|
||||
const isConnectedToPrepareRefs = this.checkIfConnectedToPrepareRefs();
|
||||
|
||||
if (isConnectedToPrepareRefs) {
|
||||
console.log('Connected to PrepareRefs node, loading bg_image_cl.png from ref folder');
|
||||
try {
|
||||
const timestamp = Date.now();
|
||||
const refImageUrl = new URL(`ref/bg_image_cl.png?t=${timestamp}`, import.meta.url).href;
|
||||
const response = await fetch(refImageUrl);
|
||||
if (!response.ok) {
|
||||
console.error('Failed to load bg_image_cl.png from ref folder');
|
||||
alert('Could not load bg_image_cl.png from ref folder. Make sure the file exists.');
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const base64Data = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result.split(',')[1]);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
|
||||
this.originalRefImageData = {
|
||||
name: 'bg_image_cl.png',
|
||||
base64: base64Data,
|
||||
type: 'image/png'
|
||||
};
|
||||
|
||||
// Clear session storage cache for this node's image to force refresh
|
||||
if (this.uuid) {
|
||||
sessionStorage.removeItem(`spline-editor-img-${this.uuid}`);
|
||||
}
|
||||
|
||||
// Get current bg_img selection to update background accordingly
|
||||
const bgImgWidget = this.widgets.find(w => w.name === "bg_img");
|
||||
const bg_img = bgImgWidget ? bgImgWidget.value : "None";
|
||||
|
||||
// Update background based on current bg_img selection
|
||||
this.updateBackgroundImage(bg_img);
|
||||
|
||||
// Wait for the image processing to complete
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
console.log('Successfully loaded bg_image_cl.png from ref folder');
|
||||
} catch (error) {
|
||||
console.error('Error loading bg_image_cl.png:', error);
|
||||
alert('Error loading bg_image_cl.png: ' + error.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get reference image from connected bg_image input
|
||||
const base64Image = await getReferenceImageFromConnectedNode(this, 'bg_image');
|
||||
if (!base64Image) {
|
||||
@@ -864,6 +1017,15 @@ app.registerExtension({
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're connected to PrepareRefs node
|
||||
const isConnectedToPrepareRefs = this.checkIfConnectedToPrepareRefs();
|
||||
|
||||
if (isConnectedToPrepareRefs) {
|
||||
// When connected to PrepareRefs, load ref images from ref folder instead
|
||||
await this.loadRefImagesFromRefFolder(activeWidget, desiredSelection);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch images from ref_images input (first frame used)
|
||||
const images = await getReferenceImagesFromConnectedNode(this);
|
||||
if (!images || images.length === 0) {
|
||||
@@ -980,6 +1142,17 @@ app.registerExtension({
|
||||
this.layerRenderer.clearRefImageCache();
|
||||
}
|
||||
|
||||
// Check if we're connected to PrepareRefs node
|
||||
const isConnectedToPrepareRefs = this.checkIfConnectedToPrepareRefs();
|
||||
|
||||
if (isConnectedToPrepareRefs) {
|
||||
// When connected to PrepareRefs, load ref images from ref folder for all box layers
|
||||
for (const boxWidget of boxWidgets) {
|
||||
await this.loadRefImagesFromRefFolder(boxWidget, boxWidget.value.ref_selection || 'ref_1');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch images from ref_images input (first frame used)
|
||||
const images = await getReferenceImagesFromConnectedNode(this);
|
||||
if (!images || images.length === 0) {
|
||||
@@ -1372,6 +1545,142 @@ app.registerExtension({
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
// Helper method to check if connected to PrepareRefs node
|
||||
this.checkIfConnectedToPrepareRefs = function() {
|
||||
// Check if any of our inputs is connected to a PrepareRefs node
|
||||
const graph = app.graph;
|
||||
if (!graph || !graph.links || !this.inputs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.inputs.length; i++) {
|
||||
const input = this.inputs[i];
|
||||
if (!input || !input.name) continue;
|
||||
|
||||
// Look for connections to this input
|
||||
let link = null;
|
||||
if (graph.links instanceof Map) {
|
||||
for (const [linkId, linkObj] of graph.links) {
|
||||
if (linkObj && linkObj.target_id === this.id && linkObj.target_slot === i) {
|
||||
link = linkObj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(graph.links)) {
|
||||
link = graph.links.find(linkObj =>
|
||||
linkObj && linkObj.target_id === this.id && linkObj.target_slot === i
|
||||
);
|
||||
}
|
||||
|
||||
if (link) {
|
||||
const sourceNode = graph._nodes?.find(n => n.id === link.origin_id);
|
||||
if (sourceNode && sourceNode.type === 'PrepareRefs') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}.bind(this);
|
||||
|
||||
// Helper method to load ref images from ref folder
|
||||
this.loadRefImagesFromRefFolder = async function(boxWidget, desiredSelection = 'ref_1') {
|
||||
try {
|
||||
// Load ALL available ref images (ref_1.png through ref_5.png) from ref folder
|
||||
const attachments = [];
|
||||
const maxRefs = 5;
|
||||
const timestamp = Date.now();
|
||||
|
||||
for (let i = 1; i <= maxRefs; i++) {
|
||||
try {
|
||||
const refImageUrl = new URL(`ref/ref_${i}.png?t=${timestamp}`, import.meta.url).href;
|
||||
const response = await fetch(refImageUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
console.log(`ref_${i}.png not found in ref folder, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const base64Data = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result.split(',')[1]);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
|
||||
// Load dimensions to fit box without stretching
|
||||
const dims = await new Promise((resolve) => {
|
||||
const img = new Image();
|
||||
img.onload = () => resolve({ width: img.width, height: img.height });
|
||||
img.onerror = () => resolve({ width: 1, height: 1 });
|
||||
img.src = `data:image/png;base64,${base64Data}`;
|
||||
});
|
||||
|
||||
// Save image to disk and store path
|
||||
const filename = `ref_${i}.png`;
|
||||
await saveRefImageToCache(base64Data, filename);
|
||||
|
||||
// Create attachment
|
||||
attachments.push({
|
||||
path: `ref/${filename}`,
|
||||
type: 'image/png',
|
||||
width: dims.width,
|
||||
height: dims.height,
|
||||
name: filename
|
||||
});
|
||||
|
||||
console.log(`Successfully loaded ref_${i}.png from ref folder`);
|
||||
} catch (error) {
|
||||
console.error(`Error loading ref_${i}.png:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
if (attachments.length === 0) {
|
||||
console.error('No ref images found in ref folder');
|
||||
return;
|
||||
}
|
||||
|
||||
// Set all attachments on the box widget
|
||||
boxWidget.value.ref_attachment = { entries: attachments };
|
||||
|
||||
// Set the desired selection if valid, otherwise set to first available
|
||||
const availableOptions = boxWidget._getRefOptions ? boxWidget._getRefOptions() : ['no_ref', 'ref_1', 'ref_2', 'ref_3', 'ref_4', 'ref_5'];
|
||||
const desiredIdx = desiredSelection && availableOptions.includes(desiredSelection)
|
||||
? Math.max(0, (parseInt(desiredSelection.split('_')[1], 10) || 1) - 1)
|
||||
: 0;
|
||||
|
||||
if (desiredIdx >= attachments.length) {
|
||||
boxWidget.value.ref_selection = 'no_ref';
|
||||
} else {
|
||||
const clampedIndex = Math.min(attachments.length - 1, desiredIdx);
|
||||
boxWidget.value.ref_selection = `ref_${clampedIndex + 1}`;
|
||||
}
|
||||
|
||||
// Persist to sessionStorage
|
||||
try {
|
||||
const keyId = this.id ?? this.uuid;
|
||||
const key = keyId ? `spline-editor-boxref-${keyId}-${boxWidget.value.name || boxWidget.name || 'box'}` : null;
|
||||
if (key) {
|
||||
sessionStorage.setItem(key, JSON.stringify({
|
||||
attachment: boxWidget.value.ref_attachment,
|
||||
selection: boxWidget.value.ref_selection,
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to persist box ref attachment to session:', e);
|
||||
}
|
||||
|
||||
// Clear ref image cache to force reload
|
||||
if (this.layerRenderer && this.layerRenderer.clearRefImageCache) {
|
||||
this.layerRenderer.clearRefImageCache();
|
||||
}
|
||||
|
||||
console.log(`Successfully loaded ${attachments.length} ref images from ref folder for box layer`);
|
||||
} catch (error) {
|
||||
console.error('Error loading ref images from ref folder:', error);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
// context menu
|
||||
this.contextMenu = document.createElement("div");
|
||||
this.contextMenu.className = 'spline-editor-context-menu';
|
||||
@@ -1488,9 +1797,10 @@ app.registerExtension({
|
||||
}
|
||||
|
||||
// Try to load cached bg_image first
|
||||
loadCachedRefImageAsBase64().then(cachedImageUrl => {
|
||||
this.loadCorrectCachedRefImage().then(cachedImageUrl => {
|
||||
if (cachedImageUrl) {
|
||||
this.loadBackgroundImageFromUrl(cachedImageUrl, 'bg_image.png', targetWidth, targetHeight);
|
||||
const filename = this.checkIfConnectedToPrepareRefs() ? 'bg_image_cl.png' : 'bg_image.png';
|
||||
this.loadBackgroundImageFromUrl(cachedImageUrl, filename, targetWidth, targetHeight);
|
||||
} else {
|
||||
// Fallback to default A.jpg
|
||||
const timestamp = Date.now();
|
||||
@@ -1685,7 +1995,7 @@ app.registerExtension({
|
||||
// Determine which image to load based on the bg_img selection
|
||||
if (bg_img === "None") {
|
||||
// Try to load cached bg_image first, then fallback to default
|
||||
loadCachedRefImageAsBase64().then(cachedImageUrl => {
|
||||
this.loadCorrectCachedRefImage().then(cachedImageUrl => {
|
||||
if (cachedImageUrl) {
|
||||
// Apply darkening effect to match onExecuted behavior
|
||||
const img = new Image();
|
||||
@@ -1726,9 +2036,9 @@ app.registerExtension({
|
||||
// Load the selected background image (A, B, or C) from the bg folder
|
||||
const timestamp = Date.now();
|
||||
const imageUrl = new URL(`bg/${bg_img}.jpg?t=${timestamp}`, import.meta.url).href;
|
||||
|
||||
|
||||
// Use the overlay function from image_overlay.js
|
||||
loadCachedRefImageAsBase64().then(cachedImageUrl => {
|
||||
this.loadCorrectCachedRefImage().then(cachedImageUrl => {
|
||||
if (cachedImageUrl) {
|
||||
createImageOverlayForConfigure(
|
||||
cachedImageUrl,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Frontend trigger for PrepareRefs backend processing
|
||||
*
|
||||
* This module provides functionality to trigger PrepareRefs processing
|
||||
* from the frontend without running the full ComfyUI workflow.
|
||||
*/
|
||||
|
||||
import { getReferenceImageFromConnectedNode } from './graph_query.js';
|
||||
|
||||
/**
|
||||
* Trigger PrepareRefs processing in the backend
|
||||
*
|
||||
* Sends lasso layer data and bg_image to backend for processing.
|
||||
* All ref images are exported as 768x768 PNG with alpha channel.
|
||||
*
|
||||
* @param {Object} node - The PrepareRefs node instance
|
||||
* @returns {Promise<Object>} Response with success status and file paths
|
||||
*/
|
||||
export async function triggerPrepareRefsBackend(node) {
|
||||
try {
|
||||
console.log('[triggerPrepareRefsBackend] Starting backend trigger...');
|
||||
|
||||
// 1. Get current bg_image from connected node or canvas
|
||||
let bgImageBase64 = null;
|
||||
|
||||
// Try to get from connected node first
|
||||
bgImageBase64 = await getReferenceImageFromConnectedNode(node, 'bg_image');
|
||||
|
||||
// Fallback: get from canvas if available
|
||||
if (!bgImageBase64 && node.refCanvasEditor?.backgroundImage) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const img = node.refCanvasEditor.backgroundImage;
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
bgImageBase64 = canvas.toDataURL('image/png');
|
||||
console.log('[triggerPrepareRefsBackend] Using bg_image from canvas');
|
||||
}
|
||||
|
||||
if (!bgImageBase64) {
|
||||
console.warn('[triggerPrepareRefsBackend] No bg_image found');
|
||||
return { success: false, error: 'No background image available' };
|
||||
}
|
||||
|
||||
// 2. Get ref_layer_data from node
|
||||
const refLayerData = node.getRefLayerData?.() || [];
|
||||
|
||||
if (refLayerData.length === 0) {
|
||||
console.warn('[triggerPrepareRefsBackend] No ref layers with shapes found');
|
||||
return { success: false, error: 'No ref layers with shapes to process' };
|
||||
}
|
||||
|
||||
console.log('[triggerPrepareRefsBackend] Found', refLayerData.length, 'layers with shapes');
|
||||
|
||||
// 3. Get dimensions
|
||||
const widthWidget = node.widgets?.find(w => w.name === 'mask_width');
|
||||
const heightWidget = node.widgets?.find(w => w.name === 'mask_height');
|
||||
const maskWidth = widthWidget?.value || 640;
|
||||
const maskHeight = heightWidget?.value || 480;
|
||||
|
||||
console.log('[triggerPrepareRefsBackend] Dimensions:', maskWidth, 'x', maskHeight);
|
||||
|
||||
// 4. Prepare payload
|
||||
const payload = {
|
||||
bg_image: bgImageBase64,
|
||||
ref_layer_data: refLayerData,
|
||||
mask_width: maskWidth,
|
||||
mask_height: maskHeight
|
||||
};
|
||||
|
||||
console.log('[triggerPrepareRefsBackend] Sending request with', refLayerData.length, 'layers');
|
||||
|
||||
// 5. Call backend endpoint
|
||||
const response = await fetch('/wanvideowrapper_qq/trigger_prepare_refs', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Backend processing failed');
|
||||
}
|
||||
|
||||
console.log('[triggerPrepareRefsBackend] Success:', result.message);
|
||||
console.log('[triggerPrepareRefsBackend] Generated files:', result.paths);
|
||||
|
||||
return result;
|
||||
|
||||
} catch (error) {
|
||||
console.error('[triggerPrepareRefsBackend] Error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error.message || 'Unknown error during backend trigger'
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user