362 lines
14 KiB
Python
362 lines
14 KiB
Python
"""
|
|
ComfyUI_Detonate - Professional Compositing Nodes for ComfyUI
|
|
|
|
Brings Nuke and Fusion-style compositing workflows to ComfyUI.
|
|
"""
|
|
|
|
# Version info
|
|
__version__ = "0.10.0"
|
|
__author__ = "ComfyUI_Detonate Contributors"
|
|
|
|
# Node mappings - will be populated as nodes are implemented
|
|
NODE_CLASS_MAPPINGS = {}
|
|
NODE_DISPLAY_NAME_MAPPINGS = {}
|
|
|
|
|
|
# Import nodes as they are implemented
|
|
|
|
# Priority 1 Nodes - Implemented ✓
|
|
try:
|
|
from .nodes.channel.premultiply import DetonatePremultiply, DetonateUnpremultiply
|
|
NODE_CLASS_MAPPINGS["DetonatePremultiply"] = DetonatePremultiply
|
|
NODE_CLASS_MAPPINGS["DetonateUnpremultiply"] = DetonateUnpremultiply
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonatePremultiply"] = "Premultiply (Detonate)"
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateUnpremultiply"] = "Unpremultiply (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Premult nodes: {e}")
|
|
|
|
try:
|
|
from .nodes.channel.shuffle import DetonateShuffle
|
|
NODE_CLASS_MAPPINGS["DetonateShuffle"] = DetonateShuffle
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateShuffle"] = "Shuffle (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Shuffle node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.blur import DetonateBlur
|
|
NODE_CLASS_MAPPINGS["DetonateBlur"] = DetonateBlur
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateBlur"] = "Blur (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Blur node: {e}")
|
|
|
|
try:
|
|
from .nodes.compositing.merge import DetonateMerge
|
|
NODE_CLASS_MAPPINGS["DetonateMerge"] = DetonateMerge
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateMerge"] = "Merge (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Merge node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.colorcorrect import DetonateColorCorrect
|
|
NODE_CLASS_MAPPINGS["DetonateColorCorrect"] = DetonateColorCorrect
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateColorCorrect"] = "ColorCorrect (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load ColorCorrect node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.grade import DetonateGrade
|
|
NODE_CLASS_MAPPINGS["DetonateGrade"] = DetonateGrade
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateGrade"] = "Grade (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Grade node: {e}")
|
|
|
|
try:
|
|
from .nodes.matte.erode_dilate import DetonateErode, DetonateDilate
|
|
NODE_CLASS_MAPPINGS["DetonateErode"] = DetonateErode
|
|
NODE_CLASS_MAPPINGS["DetonateDilate"] = DetonateDilate
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateErode"] = "Erode (Detonate)"
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateDilate"] = "Dilate (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Erode/Dilate nodes: {e}")
|
|
|
|
try:
|
|
from .nodes.transform.transform import DetonateTransform
|
|
NODE_CLASS_MAPPINGS["DetonateTransform"] = DetonateTransform
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateTransform"] = "Transform (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Transform node: {e}")
|
|
|
|
|
|
# Tier 2 Nodes - Essential Utilities ✓
|
|
try:
|
|
from .nodes.color.clamp import DetonateClamp
|
|
NODE_CLASS_MAPPINGS["DetonateClamp"] = DetonateClamp
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateClamp"] = "Clamp (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Clamp node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.invert import DetonateInvert
|
|
NODE_CLASS_MAPPINGS["DetonateInvert"] = DetonateInvert
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateInvert"] = "Invert (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Invert node: {e}")
|
|
|
|
try:
|
|
from .nodes.generator.constant import DetonateConstant
|
|
NODE_CLASS_MAPPINGS["DetonateConstant"] = DetonateConstant
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateConstant"] = "Constant (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Constant node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.saturation import DetonateSaturation
|
|
NODE_CLASS_MAPPINGS["DetonateSaturation"] = DetonateSaturation
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateSaturation"] = "Saturation (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Saturation node: {e}")
|
|
|
|
try:
|
|
from .nodes.matte.mattecontrol import DetonateMatteControl
|
|
NODE_CLASS_MAPPINGS["DetonateMatteControl"] = DetonateMatteControl
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateMatteControl"] = "MatteControl (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load MatteControl node: {e}")
|
|
|
|
try:
|
|
from .nodes.channel.channelcopy import DetonateChannelCopy
|
|
NODE_CLASS_MAPPINGS["DetonateChannelCopy"] = DetonateChannelCopy
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateChannelCopy"] = "ChannelCopy (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load ChannelCopy node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.edgedetect import DetonateEdgeDetect
|
|
NODE_CLASS_MAPPINGS["DetonateEdgeDetect"] = DetonateEdgeDetect
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateEdgeDetect"] = "EdgeDetect (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load EdgeDetect node: {e}")
|
|
|
|
|
|
# IO Nodes - File Loaders ✓
|
|
try:
|
|
from .nodes.io.load_exr import DetonateLoadEXR
|
|
NODE_CLASS_MAPPINGS["DetonateLoadEXR"] = DetonateLoadEXR
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateLoadEXR"] = "Load EXR (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load LoadEXR node: {e}")
|
|
|
|
|
|
# Cryptomatte Nodes - Object/Material ID Mattes ✓
|
|
try:
|
|
from .nodes.cryptomatte.cryptomatte_extract import DetonateCryptomatteExtract
|
|
NODE_CLASS_MAPPINGS["DetonateCryptomatteExtract"] = DetonateCryptomatteExtract
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateCryptomatteExtract"] = "Cryptomatte Extract (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Cryptomatte Extract node: {e}")
|
|
|
|
|
|
# Tier 3 Nodes - Effects & Color ✓
|
|
try:
|
|
from .nodes.filter.glow import DetonateGlow
|
|
NODE_CLASS_MAPPINGS["DetonateGlow"] = DetonateGlow
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateGlow"] = "Glow (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Glow node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.sharpen import DetonateSharpen
|
|
NODE_CLASS_MAPPINGS["DetonateSharpen"] = DetonateSharpen
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateSharpen"] = "Sharpen (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Sharpen node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.defocus import DetonateDefocus
|
|
NODE_CLASS_MAPPINGS["DetonateDefocus"] = DetonateDefocus
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateDefocus"] = "Defocus (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Defocus node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.zdefocus import DetonateZDefocus
|
|
NODE_CLASS_MAPPINGS["DetonateZDefocus"] = DetonateZDefocus
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateZDefocus"] = "ZDefocus (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load ZDefocus node: {e}")
|
|
|
|
try:
|
|
from .nodes.compositing.zmerge import DetonateZMerge
|
|
NODE_CLASS_MAPPINGS["DetonateZMerge"] = DetonateZMerge
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateZMerge"] = "ZMerge (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load ZMerge node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.colorcurves import DetonateColorCurves
|
|
NODE_CLASS_MAPPINGS["DetonateColorCurves"] = DetonateColorCurves
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateColorCurves"] = "ColorCurves (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load ColorCurves node: {e}")
|
|
|
|
try:
|
|
from .nodes.generator.ramp import DetonateRamp
|
|
NODE_CLASS_MAPPINGS["DetonateRamp"] = DetonateRamp
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateRamp"] = "Ramp (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Ramp node: {e}")
|
|
|
|
try:
|
|
from .nodes.generator.noise import DetonateNoise
|
|
NODE_CLASS_MAPPINGS["DetonateNoise"] = DetonateNoise
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateNoise"] = "Noise (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Noise node: {e}")
|
|
|
|
|
|
# Tier 4 Nodes - Production Finishing ✓
|
|
try:
|
|
from .nodes.transform.crop import DetonateCrop
|
|
NODE_CLASS_MAPPINGS["DetonateCrop"] = DetonateCrop
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateCrop"] = "Crop (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Crop node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.exposure import DetonateExposure
|
|
NODE_CLASS_MAPPINGS["DetonateExposure"] = DetonateExposure
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateExposure"] = "Exposure (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Exposure node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.vignette import DetonateVignette
|
|
NODE_CLASS_MAPPINGS["DetonateVignette"] = DetonateVignette
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateVignette"] = "Vignette (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Vignette node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.grain import DetonateGrain
|
|
NODE_CLASS_MAPPINGS["DetonateGrain"] = DetonateGrain
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateGrain"] = "Grain (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Grain node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.huesatval import DetonateHueSatVal
|
|
NODE_CLASS_MAPPINGS["DetonateHueSatVal"] = DetonateHueSatVal
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateHueSatVal"] = "HueSatVal (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load HueSatVal node: {e}")
|
|
|
|
try:
|
|
from .nodes.filter.denoise import DetonateDenoise
|
|
NODE_CLASS_MAPPINGS["DetonateDenoise"] = DetonateDenoise
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateDenoise"] = "Denoise (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load Denoise node: {e}")
|
|
|
|
try:
|
|
from .nodes.color.lut import DetonateLUT
|
|
NODE_CLASS_MAPPINGS["DetonateLUT"] = DetonateLUT
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateLUT"] = "LUT (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load LUT node: {e}")
|
|
|
|
try:
|
|
from .nodes.transform.cornerpin import DetonateCornerPin
|
|
NODE_CLASS_MAPPINGS["DetonateCornerPin"] = DetonateCornerPin
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateCornerPin"] = "CornerPin (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load CornerPin node: {e}")
|
|
|
|
|
|
# Tier 5 Nodes - Interactive Masking ✓
|
|
try:
|
|
from .nodes.matte.roto_bezier import DetonateRotoBezier, DetonateRotoBezierFromImage
|
|
NODE_CLASS_MAPPINGS["DetonateRotoBezier"] = DetonateRotoBezier
|
|
NODE_CLASS_MAPPINGS["DetonateRotoBezierFromImage"] = DetonateRotoBezierFromImage
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateRotoBezier"] = "RotoBezier (Detonate)"
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateRotoBezierFromImage"] = "RotoBezier From Image (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load RotoBezier nodes: {e}")
|
|
|
|
try:
|
|
from .nodes.matte.mask_smoother import DetonateMaskSmoother, DetonateMaskFromColor
|
|
NODE_CLASS_MAPPINGS["DetonateMaskSmoother"] = DetonateMaskSmoother
|
|
NODE_CLASS_MAPPINGS["DetonateMaskFromColor"] = DetonateMaskFromColor
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateMaskSmoother"] = "Mask Smoother (Detonate)"
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateMaskFromColor"] = "Mask From Color (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load MaskSmoother nodes: {e}")
|
|
|
|
|
|
# Tier 6 Nodes - Professional Keying ✓
|
|
try:
|
|
from .nodes.keying.chromakeyer import DetonateChromaKeyer
|
|
NODE_CLASS_MAPPINGS["DetonateChromaKeyer"] = DetonateChromaKeyer
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateChromaKeyer"] = "ChromaKeyer (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load ChromaKeyer node: {e}")
|
|
|
|
try:
|
|
from .nodes.keying.lumakeyer import DetonateLumaKeyer, DetonateLumaKeyerSimple
|
|
NODE_CLASS_MAPPINGS["DetonateLumaKeyer"] = DetonateLumaKeyer
|
|
NODE_CLASS_MAPPINGS["DetonateLumaKeyerSimple"] = DetonateLumaKeyerSimple
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateLumaKeyer"] = "LumaKeyer (Detonate)"
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateLumaKeyerSimple"] = "LumaKeyer Simple (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load LumaKeyer nodes: {e}")
|
|
|
|
|
|
# Bridge Tools - GenAI/Comp Integration ✓
|
|
try:
|
|
from .nodes.matte.edgedefringe import DetonateEdgeDefringe
|
|
NODE_CLASS_MAPPINGS["DetonateEdgeDefringe"] = DetonateEdgeDefringe
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateEdgeDefringe"] = "Edge Defringe (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load EdgeDefringe node: {e}")
|
|
|
|
try:
|
|
from .nodes.transform.displacementmap import DetonateDisplacementMap
|
|
NODE_CLASS_MAPPINGS["DetonateDisplacementMap"] = DetonateDisplacementMap
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateDisplacementMap"] = "Displacement Map (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load DisplacementMap node: {e}")
|
|
|
|
try:
|
|
from .nodes.transform.gridwarp import DetonateGridWarp
|
|
NODE_CLASS_MAPPINGS["DetonateGridWarp"] = DetonateGridWarp
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateGridWarp"] = "GridWarp (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load GridWarp node: {e}")
|
|
|
|
# Bridge Tools Round 2 - More GenAI Integration ✓
|
|
try:
|
|
from .nodes.matte.trimapgenerator import DetonateTriMapGenerator
|
|
NODE_CLASS_MAPPINGS["DetonateTriMapGenerator"] = DetonateTriMapGenerator
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateTriMapGenerator"] = "TriMap Generator (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load TriMapGenerator node: {e}")
|
|
|
|
try:
|
|
from .nodes.compositing.seamblender import DetonateSeamBlender
|
|
NODE_CLASS_MAPPINGS["DetonateSeamBlender"] = DetonateSeamBlender
|
|
NODE_DISPLAY_NAME_MAPPINGS["DetonateSeamBlender"] = "Seam Blender (Detonate)"
|
|
except ImportError as e:
|
|
print(f"Warning: Could not load SeamBlender node: {e}")
|
|
|
|
|
|
# Web directory for custom JavaScript widgets
|
|
WEB_DIRECTORY = "./web"
|
|
|
|
# Export for ComfyUI
|
|
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|
|
|
|
|
|
# Print debug info on load
|
|
print("\n" + "="*60)
|
|
print("ComfyUI_Detonate - Professional Compositing Nodes")
|
|
print(f"Version: {__version__}")
|
|
print(f"Loaded {len(NODE_CLASS_MAPPINGS)} nodes")
|
|
if NODE_CLASS_MAPPINGS:
|
|
print("\nRegistered nodes:")
|
|
for name in sorted(NODE_CLASS_MAPPINGS.keys()):
|
|
display_name = NODE_DISPLAY_NAME_MAPPINGS.get(name, name)
|
|
print(f" - {display_name}")
|
|
else:
|
|
print("\nNo nodes loaded yet - nodes will be added in development")
|
|
print("This is expected for initial setup.")
|
|
print("="*60 + "\n")
|