Added support for watermark, and regionalPrompt

This commit is contained in:
Sirshendu Ganguly
2026-03-12 14:21:38 -04:00
parent c17d46d70b
commit aa5f547b99
13 changed files with 1219 additions and 616 deletions
+7 -1
View File
@@ -26,6 +26,9 @@ from .modules.vaeSearch import vaeSearch
from .modules.referenceImages import referenceImages
from .modules.imageInferenceInputs import imageInferenceInputs
from .modules.imageInferenceAdvancedFeatures import RunwareImageInferenceAdvancedFeatures
from .modules.imageWatermarkAdvancedFeature import RunwareWatermarkAdvancedFeature
from .modules.imageRegionalPromptingAdvancedFeature import RunwareRegionalPromptingAdvancedFeature
from .modules.imageRegionalPromptingAdvancedFeatureRegions import RunwareRegionalPromptingAdvancedFeatureRegions
from .modules.videoInference import txt2vid
from .modules.videoModelSearch import videoModelSearch
from .modules.videoSettings import RunwareVideoSettings
@@ -133,7 +136,10 @@ NODE_CLASS_MAPPINGS = {
"Runware IPAdapters Combine": ipAdapterCombine,
"Runware Reference Images": referenceImages,
"Runware Image Inference Inputs": imageInferenceInputs,
"Runware Image Inference Advanced Features": RunwareImageInferenceAdvancedFeatures,
"Runware Image Advanced Feature Input": RunwareImageInferenceAdvancedFeatures,
"Runware Watermark Advanced Feature": RunwareWatermarkAdvancedFeature,
"Runware Regional Prompting Advanced Feature": RunwareRegionalPromptingAdvancedFeature,
"Runware Regional Prompting Advanced Feature Regions": RunwareRegionalPromptingAdvancedFeatureRegions,
"Runware Video Inference": txt2vid,
"Runware Video Model Search": videoModelSearch,
"Runware Frame Images": RunwareFrameImages,
+5 -1
View File
@@ -1,6 +1,6 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js";
import { promptEnhanceHandler, syncDimensionsNodeHandler, searchNodeHandler, APIKeyHandler, captionNodeHandler, mediaUUIDHandler, save3DFilepathHandler, videoTranscriptionHandler, videoOutputsHandler, handleCustomErrors, videoInferenceDimensionsHandler, videoModelSearchFilterHandler, audioModelSearchFilterHandler, vectorizeModelSearchFilterHandler, vectorizeToggleHandler, useParameterToggleHandler, imageInferenceToggleHandler, imageInferenceAdvancedFeaturesToggleHandler, watermarkAdvancedFeatureToggleHandler, regionalPromptingRegionsToggleHandler, upscalerToggleHandler, videoUpscalerToggleHandler, audioInferenceToggleHandler, audioInferenceSpeechToggleHandler, audioSettingsToggleHandler, videoSettingsToggleHandler, acceleratorOptionsToggleHandler, bytedanceProviderSettingsToggleHandler, xaiProviderSettingsToggleHandler, viduProviderSettingsToggleHandler, sourcefulProviderSettingsToggleHandler, sourcefulProviderSettingsFontsToggleHandler, threeDInferenceToggleHandler, threeDInferenceSettingsToggleHandler, threeDInferenceSettingsLatToggleHandler, ultralyticsProviderSettingsToggleHandler, openaiProviderSettingsToggleHandler, lightricksProviderSettingsToggleHandler, klingProviderSettingsToggleHandler, lumaProviderSettingsToggleHandler, briaProviderSettingsToggleHandler, pixverseProviderSettingsToggleHandler, alibabaProviderSettingsToggleHandler, mireloProviderSettingsToggleHandler, googleProviderSettingsToggleHandler, syncProviderSettingsToggleHandler, syncSegmentToggleHandler, settingsToggleHandler, audioInputToggleHandler, speechInputToggleHandler, briaProviderMaskToggleHandler, wanAnimateAdvancedFeatureSettingsToggleHandler, videoAdvancedFeatureInputsToggleHandler, audioInferenceInputsToggleHandler } from "./utils.js";
import { RUNWARE_NODE_TYPES, RUNWARE_NODE_PROPS, SEARCH_TERMS } from "./types.js";
const nodeInitList = [];
@@ -80,6 +80,10 @@ app.registerExtension({
audioInferenceToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.IMAGEINFERENCEADVANCEDFEATURES) {
imageInferenceAdvancedFeaturesToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.WATERMARKADVANCEDFEATURE) {
watermarkAdvancedFeatureToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.REGIONALPROMPTINGADVFEATUREREGIONS) {
regionalPromptingRegionsToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOINFERENCESPEECH) {
audioInferenceSpeechToggleHandler(node);
} else if(nodeClass === RUNWARE_NODE_TYPES.AUDIOSETTINGS) {
+559 -544
View File
File diff suppressed because it is too large Load Diff
+133
View File
@@ -3871,6 +3871,137 @@ function imageInferenceAdvancedFeaturesToggleHandler(advancedFeaturesNode) {
if (useHiresFixWidget && hiresFixWidget) toggleWidgetState(useHiresFixWidget, hiresFixWidget, "hiresFix");
}
function watermarkAdvancedFeatureToggleHandler(watermarkNode) {
if (!watermarkNode?.widgets) return;
function toggleWidgetState(useWidget, paramWidget, paramName) {
if (!useWidget || !paramWidget) return;
function toggleEnabled() {
const enabled = useWidget.value === true;
if (paramWidget.inputEl) {
paramWidget.inputEl.disabled = !enabled;
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
paramWidget.inputEl.readOnly = !enabled;
}
paramWidget.disabled = !enabled;
if (!paramWidget.inputEl && paramName) {
const nodeElement = watermarkNode.htmlElements?.widgetsContainer || watermarkNode.htmlElements;
if (nodeElement) {
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
if (input) {
input.disabled = !enabled;
input.style.opacity = enabled ? "1" : "0.5";
input.style.cursor = enabled ? "text" : "not-allowed";
input.readOnly = !enabled;
}
}
}
watermarkNode.setDirtyCanvas(true);
}
appendWidgetCB(useWidget, () => {
setTimeout(toggleEnabled, 50);
});
setTimeout(toggleEnabled, 100);
}
const pairs = [
["useText", "text"],
["useImage", "image"],
["useDisplayPosition", "displayPosition"],
["useTiled", "tiled"],
["useOpacity", "opacity"],
["useFontColor", "fontColor"],
["useBgColor", "bgColor"],
];
for (const [useName, paramName] of pairs) {
const useWidget = watermarkNode.widgets.find(w => w.name === useName);
const paramWidget = watermarkNode.widgets.find(w => w.name === paramName);
if (useWidget && paramWidget) {
toggleWidgetState(useWidget, paramWidget, paramName);
}
}
}
function regionalPromptingRegionsToggleHandler(regionsNode) {
if (!regionsNode?.widgets) return;
function toggleWidgetState(useWidget, paramWidgets, paramNames) {
if (!useWidget || !paramWidgets || paramWidgets.length === 0) return;
function toggleEnabled() {
const enabled = useWidget.value === true;
for (let i = 0; i < paramWidgets.length; i++) {
const paramWidget = paramWidgets[i];
const paramName = paramNames[i];
if (!paramWidget) continue;
if (paramWidget.inputEl) {
paramWidget.inputEl.disabled = !enabled;
paramWidget.inputEl.style.opacity = enabled ? "1" : "0.5";
paramWidget.inputEl.style.cursor = enabled ? "text" : "not-allowed";
paramWidget.inputEl.readOnly = !enabled;
}
paramWidget.disabled = !enabled;
if (!paramWidget.inputEl && paramName) {
const nodeElement = regionsNode.htmlElements?.widgetsContainer || regionsNode.htmlElements;
if (nodeElement) {
const input = nodeElement.querySelector(`input[name="${paramName}"], textarea[name="${paramName}"], select[name="${paramName}"]`);
if (input) {
input.disabled = !enabled;
input.style.opacity = enabled ? "1" : "0.5";
input.style.cursor = enabled ? "text" : "not-allowed";
input.readOnly = !enabled;
}
}
}
}
regionsNode.setDirtyCanvas(true);
}
appendWidgetCB(useWidget, () => {
setTimeout(toggleEnabled, 50);
});
setTimeout(toggleEnabled, 100);
}
for (let idx = 1; idx <= 4; idx++) {
const useWidget = regionsNode.widgets.find(w => w.name === `useRegion${idx}`);
const promptWidget = regionsNode.widgets.find(w => w.name === `region${idx}Prompt`);
const x0Widget = regionsNode.widgets.find(w => w.name === `region${idx}_x0`);
const y0Widget = regionsNode.widgets.find(w => w.name === `region${idx}_y0`);
const x1Widget = regionsNode.widgets.find(w => w.name === `region${idx}_x1`);
const y1Widget = regionsNode.widgets.find(w => w.name === `region${idx}_y1`);
const paramWidgets = [promptWidget, x0Widget, y0Widget, x1Widget, y1Widget];
const paramNames = [
`region${idx}Prompt`,
`region${idx}_x0`,
`region${idx}_y0`,
`region${idx}_x1`,
`region${idx}_y1`,
];
if (useWidget) {
toggleWidgetState(useWidget, paramWidgets, paramNames);
}
}
}
function audioInferenceInputsToggleHandler(audioInputsNode) {
// Find widgets
const useVideoWidget = audioInputsNode.widgets.find(w => w.name === "useVideo");
@@ -3990,6 +4121,8 @@ export {
useParameterToggleHandler,
imageInferenceToggleHandler,
imageInferenceAdvancedFeaturesToggleHandler,
watermarkAdvancedFeatureToggleHandler,
regionalPromptingRegionsToggleHandler,
upscalerToggleHandler,
videoUpscalerToggleHandler,
audioInferenceToggleHandler,
+1 -1
View File
@@ -195,7 +195,7 @@ class txt2img:
"tooltip": "Connect Runware Image Inference Ultralytics node to configure Ultralytics parameters (maskBlur, maskPadding, confidence, prompts, steps, CFGScale, strength).",
}),
"advancedFeatures": ("RUNWAREIMAGEINFERENCEADVANCEDFEATURES", {
"tooltip": "Connect Runware Image Inference Advanced Features for layerDiffuse (transparency) and hiresFix (two-stage high-res).",
"tooltip": "Connect Runware Image Advanced Feature Input for layerDiffuse (transparency) and hiresFix (two-stage high-res).",
}),
}
}
+80 -69
View File
@@ -1,69 +1,80 @@
"""
Runware Image Inference Advanced Features Node
Provides advancedFeatures (layerDiffuse, hiresFix) for Runware Image Inference.
"""
from typing import Dict, Any
class RunwareImageInferenceAdvancedFeatures:
"""Runware Image Inference Advanced Features Node"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"useLayerDiffuse": ("BOOLEAN", {
"tooltip": "Enable to include layerDiffuse in advancedFeatures. When enabled, LayerDiffuse generates images with transparency (alpha) without post-processing background removal.",
"default": False,
}),
"layerDiffuse": ("BOOLEAN", {
"tooltip": "Enable LayerDiffuse technology for direct generation of images with transparency (alpha channels). Only used when 'Use Layer Diffuse' is enabled.",
"default": False,
"label_on": "true",
"label_off": "false",
}),
"useHiresFix": ("BOOLEAN", {
"tooltip": "Enable to include hiresFix in advancedFeatures. When enabled, uses a two-stage process for higher-resolution, higher-detail images.",
"default": False,
}),
"hiresFix": ("BOOLEAN", {
"tooltip": "Enable a two-stage generation: first at native resolution, then upscale and refine in a second pass. Only used when 'Use Hires Fix' is enabled.",
"default": False,
"label_on": "true",
"label_off": "false",
}),
}
}
RETURN_TYPES = ("RUNWAREIMAGEINFERENCEADVANCEDFEATURES",)
RETURN_NAMES = ("advancedFeatures",)
FUNCTION = "createAdvancedFeatures"
CATEGORY = "Runware"
DESCRIPTION = "Configure advanced features for Runware Image Inference (layerDiffuse for transparency, hiresFix for two-stage high-res generation). Connect to Runware Image Inference advancedFeatures input."
def createAdvancedFeatures(self, **kwargs) -> tuple:
"""Build advancedFeatures dict for the API."""
use_layer_diffuse = kwargs.get("useLayerDiffuse", False)
layer_diffuse = kwargs.get("layerDiffuse", False)
use_hires_fix = kwargs.get("useHiresFix", False)
hires_fix = kwargs.get("hiresFix", False)
advanced_features: Dict[str, Any] = {}
if use_layer_diffuse:
advanced_features["layerDiffuse"] = bool(layer_diffuse)
if use_hires_fix:
advanced_features["hiresFix"] = bool(hires_fix)
return (advanced_features,)
NODE_CLASS_MAPPINGS = {
"RunwareImageInferenceAdvancedFeatures": RunwareImageInferenceAdvancedFeatures,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareImageInferenceAdvancedFeatures": "Runware Image Inference Advanced Features",
}
from typing import Dict, Any
class RunwareImageInferenceAdvancedFeatures:
"""Runware Image Advanced Feature Input Node"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"useLayerDiffuse": ("BOOLEAN", {
"tooltip": "Enable to include layerDiffuse in advancedFeatures. When enabled, LayerDiffuse generates images with transparency (alpha) without post-processing background removal.",
"default": False,
}),
"layerDiffuse": ("BOOLEAN", {
"tooltip": "Enable LayerDiffuse technology for direct generation of images with transparency (alpha channels). Only used when 'Use Layer Diffuse' is enabled.",
"default": False,
"label_on": "true",
"label_off": "false",
}),
"useHiresFix": ("BOOLEAN", {
"tooltip": "Enable to include hiresFix in advancedFeatures. When enabled, uses a two-stage process for higher-resolution, higher-detail images.",
"default": False,
}),
"hiresFix": ("BOOLEAN", {
"tooltip": "Enable a two-stage generation: first at native resolution, then upscale and refine in a second pass. Only used when 'Use Hires Fix' is enabled.",
"default": False,
"label_on": "true",
"label_off": "false",
}),
"watermark": ("RUNWAREIMAGEWATERMARKADVFEATURE", {
"tooltip": "Connect Runware Watermark Advanced Feature to include watermark configuration in advancedFeatures.watermark.",
}),
"regionalPrompting": ("RUNWAREREGIONALPROMPTINGADVFEATURE", {
"tooltip": "Connect Runware Regional Prompting Advanced Feature to configure regionalPrompting in advancedFeatures.",
}),
},
}
RETURN_TYPES = ("RUNWAREIMAGEINFERENCEADVANCEDFEATURES",)
RETURN_NAMES = ("advancedFeatures",)
FUNCTION = "createAdvancedFeatures"
CATEGORY = "Runware"
DESCRIPTION = (
"Configure advanced features for Runware Image Inference: layerDiffuse (transparency), "
"hiresFix (two-stage high-res), watermark, and regional prompting. "
"Connect to Runware Image Inference advancedFeatures input."
)
def createAdvancedFeatures(self, watermark=None, regionalPrompting=None, **kwargs) -> tuple:
"""Build advancedFeatures dict for the API."""
use_layer_diffuse = kwargs.get("useLayerDiffuse", False)
layer_diffuse = kwargs.get("layerDiffuse", False)
use_hires_fix = kwargs.get("useHiresFix", False)
hires_fix = kwargs.get("hiresFix", False)
advanced_features: Dict[str, Any] = {}
if use_layer_diffuse:
advanced_features["layerDiffuse"] = bool(layer_diffuse)
if use_hires_fix:
advanced_features["hiresFix"] = bool(hires_fix)
if isinstance(watermark, dict) and watermark:
advanced_features["watermark"] = watermark
if isinstance(regionalPrompting, dict) and regionalPrompting:
advanced_features["regionalPrompting"] = regionalPrompting
return (advanced_features,)
NODE_CLASS_MAPPINGS = {
"RunwareImageInferenceAdvancedFeatures": RunwareImageInferenceAdvancedFeatures,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareImageInferenceAdvancedFeatures": "Runware Image Advanced Feature Input",
}
@@ -0,0 +1,80 @@
from typing import Dict, Any, Tuple
class RunwareRegionalPromptingAdvancedFeature:
"""
Runware Regional Prompting Advanced Feature Node
Builds the advancedFeatures.regionalPrompting configuration object:
- injectSteps
- backgroundPrompt
- baseRatio
- regions (connected from the Regions node)
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"injectSteps": ("INT", {
"tooltip": "Steps to inject regional masks (1-100).",
"default": 15,
"min": 1,
"max": 100,
}),
"backgroundPrompt": ("STRING", {
"tooltip": "Background prompt applied to uncovered areas.",
"default": "",
}),
"baseRatio": ("FLOAT", {
"tooltip": "Base prompt attention weight (0.0 - 1.0).",
"default": 0.0,
"min": 0.0,
"max": 1.0,
"step": 0.01,
}),
"regions": ("RUNWAREREGIONALPROMPTINGREGIONS", {
"tooltip": "Connect Runware Regional Prompting Advanced Feature Regions node to define regional prompts and masks.",
}),
},
}
RETURN_TYPES: Tuple[str] = ("RUNWAREREGIONALPROMPTINGADVFEATURE",)
RETURN_NAMES = ("regionalPrompting",)
FUNCTION = "createRegionalPrompting"
CATEGORY = "Runware"
DESCRIPTION = (
"Configure regional prompting advanced feature (injectSteps, backgroundPrompt, "
"baseRatio, and regions). Connect output to Runware Image Advanced Feature Input "
"regionalPrompting input."
)
def createRegionalPrompting(self, regions=None, **kwargs) -> tuple:
"""Build regionalPrompting dict for advancedFeatures.regionalPrompting."""
inject_steps = int(kwargs.get("injectSteps", 15))
base_ratio = float(kwargs.get("baseRatio", 0.2))
background_prompt = (kwargs.get("backgroundPrompt", "") or "").strip()
config: Dict[str, Any] = {
"injectSteps": inject_steps,
"baseRatio": base_ratio,
}
if background_prompt:
config["backgroundPrompt"] = background_prompt
if isinstance(regions, list) and regions:
config["regions"] = regions
return (config,)
NODE_CLASS_MAPPINGS = {
"RunwareRegionalPromptingAdvancedFeature": RunwareRegionalPromptingAdvancedFeature,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareRegionalPromptingAdvancedFeature": "Runware Regional Prompting Advanced Feature",
}
@@ -0,0 +1,196 @@
from typing import Dict, Any, List, Tuple
class RunwareRegionalPromptingAdvancedFeatureRegions:
"""
Runware Regional Prompting Advanced Feature Regions Node
Builds the advancedFeatures.regionalPrompting.regions array, with up to 4 regions.
Each region has a prompt and a rectangular mask [x0, y0, x1, y1].
"""
@classmethod
def INPUT_TYPES(cls):
coords_tooltip = "Mask rectangle as [x0, y0, x1, y1] in image pixel coordinates."
return {
"required": {},
"optional": {
# Region 1
"useRegion1": ("BOOLEAN", {
"tooltip": "Enable first regional prompt mask.",
"default": False,
}),
"region1Prompt": ("STRING", {
"tooltip": "Prompt for region 1.",
"default": "",
}),
"region1_x0": ("INT", {
"tooltip": coords_tooltip,
"default": 0,
"min": 0,
"max": 8192,
}),
"region1_y0": ("INT", {
"tooltip": coords_tooltip,
"default": 0,
"min": 0,
"max": 8192,
}),
"region1_x1": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
"region1_y1": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
# Region 2
"useRegion2": ("BOOLEAN", {
"tooltip": "Enable second regional prompt mask.",
"default": False,
}),
"region2Prompt": ("STRING", {
"tooltip": "Prompt for region 2.",
"default": "",
}),
"region2_x0": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
"region2_y0": ("INT", {
"tooltip": coords_tooltip,
"default": 0,
"min": 0,
"max": 8192,
}),
"region2_x1": ("INT", {
"tooltip": coords_tooltip,
"default": 1024,
"min": 0,
"max": 8192,
}),
"region2_y1": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
# Region 3
"useRegion3": ("BOOLEAN", {
"tooltip": "Enable third regional prompt mask.",
"default": False,
}),
"region3Prompt": ("STRING", {
"tooltip": "Prompt for region 3.",
"default": "",
}),
"region3_x0": ("INT", {
"tooltip": coords_tooltip,
"default": 0,
"min": 0,
"max": 8192,
}),
"region3_y0": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
"region3_x1": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
"region3_y1": ("INT", {
"tooltip": coords_tooltip,
"default": 1024,
"min": 0,
"max": 8192,
}),
# Region 4
"useRegion4": ("BOOLEAN", {
"tooltip": "Enable fourth regional prompt mask.",
"default": False,
}),
"region4Prompt": ("STRING", {
"tooltip": "Prompt for region 4.",
"default": "",
}),
"region4_x0": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
"region4_y0": ("INT", {
"tooltip": coords_tooltip,
"default": 512,
"min": 0,
"max": 8192,
}),
"region4_x1": ("INT", {
"tooltip": coords_tooltip,
"default": 1024,
"min": 0,
"max": 8192,
}),
"region4_y1": ("INT", {
"tooltip": coords_tooltip,
"default": 1024,
"min": 0,
"max": 8192,
}),
},
}
RETURN_TYPES: Tuple[str] = ("RUNWAREREGIONALPROMPTINGREGIONS",)
RETURN_NAMES = ("regions",)
FUNCTION = "createRegions"
CATEGORY = "Runware"
DESCRIPTION = (
"Configure regions array for regional prompting. Each enabled region provides "
"a prompt and a rectangular mask [x0, y0, x1, y1]. Connect to Runware Regional "
"Prompting Advanced Feature regions input."
)
def createRegions(self, **kwargs) -> tuple:
"""Build list of regional prompting regions."""
regions: List[Dict[str, Any]] = []
for idx in range(1, 5):
use_region = kwargs.get(f"useRegion{idx}", False)
prompt = (kwargs.get(f"region{idx}Prompt", "") or "").strip()
if not use_region or not prompt:
continue
x0 = int(kwargs.get(f"region{idx}_x0", 0))
y0 = int(kwargs.get(f"region{idx}_y0", 0))
x1 = int(kwargs.get(f"region{idx}_x1", 0))
y1 = int(kwargs.get(f"region{idx}_y1", 0))
mask = [x0, y0, x1, y1]
regions.append(
{
"prompt": prompt,
"mask": mask,
}
)
return (regions,)
NODE_CLASS_MAPPINGS = {
"RunwareRegionalPromptingAdvancedFeatureRegions": RunwareRegionalPromptingAdvancedFeatureRegions,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareRegionalPromptingAdvancedFeatureRegions": "Runware Regional Prompting Advanced Feature Regions",
}
+154
View File
@@ -0,0 +1,154 @@
from typing import Dict, Any, Tuple
from .utils.runwareUtils import convertTensor2IMG
class RunwareWatermarkAdvancedFeature:
"""Runware Watermark Advanced Feature Node"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {
"useText": ("BOOLEAN", {
"tooltip": "Enable to set text content for the watermark (2-32 characters).",
"default": False,
}),
"text": ("STRING", {
"tooltip": "Text content for the watermark (2-32 characters). Only used when 'Use Text' is enabled.",
"default": "",
}),
"useImage": ("BOOLEAN", {
"tooltip": "Enable to set image content for the watermark (connect an IMAGE, UUID, URL, data URI, or base64).",
"default": False,
}),
"image": ("IMAGE", {
"tooltip": "Image to use as watermark. Can be connected from a Load Image node; internally converted to a data URI/UUID when used.",
}),
"useDisplayPosition": ("BOOLEAN", {
"tooltip": "Enable to set watermark display position.",
"default": False,
}),
"displayPosition": ([
"top-left", "top-center", "top-right",
"center-left", "center-center", "center-right",
"bottom-left", "bottom-center", "bottom-right",
], {
"tooltip": "Watermark position on the image.",
"default": "bottom-right",
}),
"useTiled": ("BOOLEAN", {
"tooltip": "Enable to tile the watermark across the image at -45 degrees.",
"default": False,
}),
"tiled": ("BOOLEAN", {
"tooltip": "When enabled, distribute watermark across the image at -45 degrees. Only used when 'Use Tiled' is enabled.",
"default": False,
"label_on": "true",
"label_off": "false",
}),
"useOpacity": ("BOOLEAN", {
"tooltip": "Enable to set watermark opacity (0.1 - 1.0).",
"default": False,
}),
"opacity": ("FLOAT", {
"tooltip": "Watermark opacity (0.1 - 1.0). Only used when 'Use Opacity' is enabled.",
"default": 0.6,
"min": 0.1,
"max": 1.0,
"step": 0.05,
}),
"useFontColor": ("BOOLEAN", {
"tooltip": "Enable to set watermark font color (hex).",
"default": False,
}),
"fontColor": ("STRING", {
"tooltip": "Text color in hex format (e.g. #ffffff). Only used when 'Use Font Color' is enabled.",
"default": "#ffffff",
}),
"useBgColor": ("BOOLEAN", {
"tooltip": "Enable to set watermark background color (hex).",
"default": False,
}),
"bgColor": ("STRING", {
"tooltip": "Background color in hex format (e.g. #000000 or transparent). Only used when 'Use Bg Color' is enabled.",
"default": "transparent",
}),
},
}
RETURN_TYPES: Tuple[str] = ("RUNWAREIMAGEWATERMARKADVFEATURE",)
RETURN_NAMES = ("watermark",)
FUNCTION = "createWatermark"
CATEGORY = "Runware"
DESCRIPTION = (
"Configure watermark advanced feature for Runware Image Inference. "
"You must provide exactly one of text or image. Connect output to "
"Runware Image Advanced Feature Input watermark connection."
)
def createWatermark(self, **kwargs) -> tuple:
"""Build watermark dict for advancedFeatures.watermark."""
use_text = kwargs.get("useText", False)
text = (kwargs.get("text", "") or "").strip()
use_image = kwargs.get("useImage", False)
raw_image = kwargs.get("image", None)
has_text = use_text and bool(text)
image_str: str = ""
if use_image and raw_image is not None:
# If an IMAGE tensor is connected, convert it to a data URI / UUID.
try:
# convertTensor2IMG handles caching and returns either UUID or data URI.
image_str = convertTensor2IMG(raw_image)
except Exception:
image_str = ""
has_image = use_image and bool(image_str)
if has_text == has_image:
raise Exception(
"Watermark configuration requires exactly one of text or image (but not both or neither)."
)
use_pos = kwargs.get("useDisplayPosition", False)
pos = kwargs.get("displayPosition", "bottom-right")
use_tiled = kwargs.get("useTiled", False)
tiled = bool(kwargs.get("tiled", False))
use_opacity = kwargs.get("useOpacity", False)
opacity = float(kwargs.get("opacity", 0.6))
use_font = kwargs.get("useFontColor", False)
font_color = (kwargs.get("fontColor", "#ffffff") or "").strip()
use_bg = kwargs.get("useBgColor", False)
bg_color = (kwargs.get("bgColor", "transparent") or "").strip()
watermark: Dict[str, Any] = {}
if has_text:
watermark["text"] = text
if has_image:
watermark["image"] = image_str
if use_pos:
watermark["displayPosition"] = pos
if use_tiled:
watermark["tiled"] = tiled
if use_opacity:
watermark["opacity"] = opacity
if use_font and font_color:
watermark["fontColor"] = font_color
if use_bg and bg_color:
watermark["bgColor"] = bg_color
return (watermark,)
NODE_CLASS_MAPPINGS = {
"RunwareWatermarkAdvancedFeature": RunwareWatermarkAdvancedFeature,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RunwareWatermarkAdvancedFeature": "Runware Watermark Advanced Feature",
}
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
File diff suppressed because one or more lines are too long