Added support for multiple images as RefImages

This commit is contained in:
Sirshendu Ganguly
2026-04-24 19:17:14 +05:30
parent 47b637bd26
commit c30cbd5bb2
7 changed files with 88 additions and 25 deletions
+3
View File
@@ -98,6 +98,7 @@ from .modules.vectorize import vectorize
from .modules.videoBgRemoval import videoBgRemoval
from .modules.videoUpscaler import videoUpscaler
from .modules.videoInputsReferences import videoInputsReferences
from .modules.videoInputsReferenceImagesMultipleImagesConnector import RunwareVideoInputsReferenceImagesMultipleImagesConnector
from .modules.videoInputsFrame import RunwareVideoInputsFrameImages
from .modules.safetyInputs import safetyInputs
from .modules.settings import RunwareSettings
@@ -229,6 +230,7 @@ NODE_CLASS_MAPPINGS = {
"Runware Video Background Removal": videoBgRemoval,
"Runware Video Upscaler": videoUpscaler,
"Runware Video Inference Inputs Reference Images": videoInputsReferences,
"Runware Video Inference Inputs Reference Images Multiple Images Connector": RunwareVideoInputsReferenceImagesMultipleImagesConnector,
"Runware Video Inputs Frame Images": RunwareVideoInputsFrameImages,
"Runware Safety Inputs": safetyInputs,
"Runware Settings": RunwareSettings,
@@ -268,6 +270,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Runware Video Inference Inputs Reference Videos": "Runware Video Inference Inputs Reference Videos",
"Runware Reference Audios": "Runware Video Inference Inputs Reference Audios",
"Runware Video Inference Inputs Reference Audios": "Runware Video Inference Inputs Reference Audios",
"Runware Video Inference Inputs Reference Images Multiple Images Connector": "Runware Video Inference Inputs Reference Images Multiple Images Connector",
}
WEB_DIRECTORY = "./clientlibs"
+5
View File
@@ -112,6 +112,7 @@ const RUNWARE_NODE_TYPES = {
REFERENCEVOICES_LEGACY: "Runware Reference Voices",
REFERENCEAUDIOS: "Runware Video Inference Inputs Reference Audios",
VIDEOINPUTSREFERENCES_LEGACY: "Runware Video Inputs References",
VIDEOINPUTSREFERENCEMULTIIMAGES: "Runware Video Inference Inputs Reference Images Multiple Images Connector",
VIDEOINFERENCEINPUTS: "Runware Video Inference Inputs",
VIDEOINFERENCEELEMENTS: "Runware Video Inference Elements",
VIDEOINFERENCEELEMENTSCOMBINE: "Runware Video Inference Elements Combine",
@@ -434,6 +435,10 @@ const RUNWARE_NODE_PROPS = {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.VIDEOINPUTSREFERENCEMULTIIMAGES]: {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
},
[RUNWARE_NODE_TYPES.VIDEOINFERENCEELEMENTS]: {
bgColor: DEFAULT_BGCOLOR,
colorModeOnly: true,
@@ -0,0 +1,46 @@
from typing import List
from .utils import runwareUtils as rwUtils
class RunwareVideoInputsReferenceImagesMultipleImagesConnector:
"""Collect up to 4 images for one referenceImages entry."""
MAX_IMAGES = 4
@classmethod
def INPUT_TYPES(cls):
optionalInputs = {}
for i in range(1, cls.MAX_IMAGES + 1):
optionalInputs[f"Image{i}"] = ("IMAGE", {
"tooltip": f"Optional image {i} for this reference group.",
})
return {
"required": {},
"optional": optionalInputs,
}
DESCRIPTION = (
"Collect up to 4 images for one referenceImages item. "
"Connect this output to Images1/Images2/... on Runware Video Inference Inputs Reference Images."
)
FUNCTION = "createImages"
RETURN_TYPES = ("RUNWAREVIDEOINPUTSREFERENCEMULTIIMAGES",)
RETURN_NAMES = ("Images",)
CATEGORY = "Runware"
def createImages(self, **kwargs) -> tuple[List[str]]:
images: List[str] = []
for i in range(1, self.MAX_IMAGES + 1):
image = kwargs.get(f"Image{i}")
if image is not None:
images.append(rwUtils.convertTensor2IMG(image))
return (images,)
NODE_CLASS_MAPPINGS = {
"RunwareVideoInputsReferenceImagesMultipleImagesConnector": RunwareVideoInputsReferenceImagesMultipleImagesConnector,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareVideoInputsReferenceImagesMultipleImagesConnector": "Runware Video Inference Inputs Reference Images Multiple Images Connector",
}
+32 -24
View File
@@ -14,18 +14,21 @@ class videoInputsReferences:
for i in range(1, cls.MAX_REFERENCES + 1):
ordinal = rwUtils.getOrdinal(i)
optionalInputs[f"Image{i}"] = ("IMAGE", {
"tooltip": f"{ordinal.capitalize()} reference image (primary image for this reference entry).",
"tooltip": f"{ordinal.capitalize()} single reference image (mutually exclusive with Images{i}).",
})
optionalInputs[f"Images{i}"] = ("RUNWAREVIDEOINPUTSREFERENCEMULTIIMAGES", {
"tooltip": f"{ordinal.capitalize()} reference image group from the Multiple Images Connector (mutually exclusive with Image{i}).",
})
optionalInputs[f"Tag{i}"] = ("STRING", {
"tooltip": f"Optional tag for the {ordinal} reference (e.g., @image{i}, @Actor-1).",
"default": "",
})
optionalInputs[f"Type{i}"] = ("STRING", {
"tooltip": f"Type for the {ordinal} reference (e.g., grid or image).",
"tooltip": f"Type for the {ordinal} reference (e.g., image or grid). Leave empty to omit.",
"default": "",
})
optionalInputs[f"Audio{i}"] = ("STRING", {
"tooltip": f"Optional audio URL/mediaUUID for the {ordinal} reference (supported for type=image).",
"tooltip": f"Optional audio URL/mediaUUID for the {ordinal} reference.",
"default": "",
})
@@ -35,8 +38,8 @@ class videoInputsReferences:
}
DESCRIPTION = (
"Configure multiple reference image entries for video inference inputs, "
"with optional tag, type, images list, and audio per entry."
"Configure multiple reference image entries for video inference inputs. "
"For each slot, provide either ImageN (single image) or ImagesN (connector output), not both."
)
FUNCTION = "createReferences"
RETURN_TYPES = ("RUNWAREVIDEOINPUTSREFERENCEIMAGES",)
@@ -45,43 +48,48 @@ class videoInputsReferences:
def createReferences(self, **kwargs) -> tuple[List[Any]]:
"""Create list of reference entries from provided parameters."""
references = []
references: List[Any] = []
for i in range(1, self.MAX_REFERENCES + 1):
imageKey = f"Image{i}"
imagesKey = f"Images{i}"
tagKey = f"Tag{i}"
typeKey = f"Type{i}"
audioKey = f"Audio{i}"
image = kwargs.get(imageKey)
images = kwargs.get(imagesKey)
refTag = (kwargs.get(tagKey) or "").strip()
refType = (kwargs.get(typeKey) or "").strip()
refType = kwargs.get(typeKey, "")
refAudio = (kwargs.get(audioKey) or "").strip()
has_image = image is not None
has_images = isinstance(images, list) and len(images) > 0
if has_image and has_images:
raise ValueError(
f"Reference {i}: use either {imageKey} or {imagesKey}, not both."
)
if image is not None:
reference = self._createReference(image, refTag, refType, refAudio)
if has_image or has_images:
reference = self._createReference(image, images, refTag, refType, refAudio)
references.append(reference)
return (references,)
def _createReference(self, image, refTag: str, refType: str, refAudio: str):
"""
Backward compatible behavior:
- If no extra metadata is provided, return legacy string entry.
- If tag/type/images/audio are provided, return object entry.
"""
imageUrl = rwUtils.convertTensor2IMG(image)
images = [imageUrl]
def _createReference(self, image, images, refTag: str, refType: str, refAudio: str):
"""Create reference entry."""
entry: Dict[str, Any] = {}
if image is not None:
entry["image"] = rwUtils.convertTensor2IMG(image)
elif isinstance(images, list) and len(images) > 0:
entry["images"] = images
else:
return entry
has_extended_fields = bool(refTag or refType or refAudio or len(images) > 1)
if not has_extended_fields:
return imageUrl
entry: Dict[str, Any] = {"images": images}
if refTag:
entry["tag"] = refTag
if refType:
entry["type"] = refType
if isinstance(refType, str) and refType.strip():
entry["type"] = refType.strip()
if refAudio:
entry["audio"] = refAudio
return entry
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long