1410 lines
90 KiB
Python
1410 lines
90 KiB
Python
from ..components.tree import TREE_RASTERIX
|
|
from ..components.tree import PRIMERE_ROOT
|
|
import random
|
|
import folder_paths
|
|
|
|
from ..components.images import img_shade_level as img_shade_level
|
|
from ..components.images import img_brightness_contrast as img_brightness_contrast
|
|
from ..components.images import img_color_balance as img_color_balance
|
|
from ..components.images import img_hue_saturation as img_hue_saturation
|
|
from ..components.images import img_levels_auto as img_levels_auto
|
|
from ..components.images import isgen_detect_ext_full as isgen_detect_ext_full
|
|
from ..components.images import img_film_grain as img_film_grain
|
|
from ..components.images import img_blur as img_blur
|
|
from ..components.images import img_selective_tone as img_selective_tone
|
|
from ..components.images import img_smart_lighting as img_smart_lighting
|
|
from ..components.images import img_white_balance as img_white_balance
|
|
from ..components.images import img_film_rendering as img_film_rendering
|
|
from ..components.images.img_film_rendering import FILM_PRESETS
|
|
from ..components.images import img_lens_effects as img_lens_effects
|
|
from ..components.images import img_levels_compress as img_levels_compress
|
|
from ..components.images import img_dithering as img_dithering
|
|
from ..components.images import histogram as histogram
|
|
from ..components.images import img_posterize as img_posterize
|
|
from ..components.images import img_solarization_bw as img_solarization_bw
|
|
from ..components.images import img_clarity as img_clarity
|
|
from ..components.images import img_dehaze as img_dehaze
|
|
from ..components.images import img_local_laplacian as img_local_laplacian
|
|
from ..components.images import img_frequency_separation as img_frequency_separation
|
|
from ..components.images import img_filmic_curve as img_filmic_curve
|
|
from ..components.images import img_lut3d as img_lut3d
|
|
from ..components.images import img_edge_jitter as img_edge_jitter
|
|
from ..components.images import img_depth_blur as img_depth_blur
|
|
from ..components.images import img_photo_paper as img_photo_paper
|
|
from ..components.images.img_photo_paper import PAPER_PRESETS
|
|
|
|
from ..components import utility
|
|
from .Dashboard import PrimereModelConceptSelector as PrimereModelConceptSelector
|
|
import os
|
|
from server import PromptServer
|
|
from types import SimpleNamespace
|
|
|
|
FILM_PRESETS_BY_TYPE = img_film_rendering.list_presets_by_type()
|
|
FILM_TYPES = ["All"] + sorted(FILM_PRESETS_BY_TYPE.keys())
|
|
|
|
class PrimereRasterix:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_rasterix"
|
|
CATEGORY = TREE_RASTERIX
|
|
OUTPUT_NODE = True
|
|
|
|
MODELLIST = PrimereModelConceptSelector.MODELLIST
|
|
CONCEPT_LIST = PrimereModelConceptSelector.CONCEPT_LIST
|
|
FILM_TYPES = FILM_TYPES
|
|
FILM_PRESETS_BY_TYPE = FILM_PRESETS_BY_TYPE
|
|
|
|
LUT_DIR = os.path.join(PRIMERE_ROOT, 'components', 'images', 'luts')
|
|
|
|
SECTION_TITLES = [
|
|
{"before": "concepts", "name": "rasterix_main", "title": "🧭 Project Setup", "color": "#1B263B", "text_color": "#EAF1F8", "label": "Choose model concept/model for save-load profiles and set precision for the full pipeline."},
|
|
|
|
{"after": "precision", "name": "rasterix_auto_levels", "title": "🎚 Auto Levels & Gamma", "color": "#243B55", "text_color": "#EAF1F8", "label": "Photoshop-style auto levels with threshold protection and optional target gamma alignment. Inspired by Adobe Photoshop."},
|
|
{"after": "gamma_target", "name": "rasterix_white_balance", "title": "🔦 White Balance", "color": "#243B55", "text_color": "#EAF1F8", "label": "Correct temperature and tint first to establish a neutral color baseline for later grading. Inspired by Adobe Camera Raw and DxO Photolab."},
|
|
{"after": "wb_tint", "name": "rasterix_smart_lighting", "title": "💡 Smart Lighting", "color": "#243B55", "text_color": "#EAF1F8", "label": "Adaptive light shaping to recover perceived depth and readability before local effects. Inspired by DxO Photolab"},
|
|
|
|
{"after": "smart_lighting", "name": "rasterix_dehaze", "title": "🌫 Atmosphere: Dehaze", "color": "#0F3443", "text_color": "#EAF1F8", "label": "Reduce haze and veiling glow while preserving natural contrast and color balance. Inspired by Adobe Lightroom Dehaze."},
|
|
{"after": "dehaze_contrast", "name": "rasterix_depth_blur", "title": "🌀 Atmosphere: Depth Blur", "color": "#0F3443", "text_color": "#EAF1F8", "label": "Depth-guided lens blur to separate subject and background with controllable focus falloff."},
|
|
{"after": "depth_gamma", "name": "rasterix_blur", "title": "🫗 Atmosphere: Creative Blur", "color": "#0F3443", "text_color": "#EAF1F8", "label": "Apply additional blur styles for softness, abstraction, or cinematic diffusion."},
|
|
|
|
{"after": "edge_threshold", "name": "rasterix_brightness_contrast", "title": "🧊 Tone: Brightness & Contrast", "color": "#1A2A6C", "text_color": "#EAF1F8", "label": "Global tone shaping for exposure feel and contrast punch after atmospheric corrections. Inspired by Adobe Photoshop."},
|
|
{"after": "use_legacy", "name": "rasterix_portrait_retouch", "title": "🪒 Tone: Portrait Retouch", "color": "#1A2A6C", "text_color": "#EAF1F8", "label": "Frequency-based skin and texture workflow for gentle portrait cleanup and separation. Inspired by professional Photoshop retouch workflows."},
|
|
{"after": "blend_mode", "name": "rasterix_local_laplacian", "title": "🧱 Tone: Edge-Aware Pyramid", "color": "#1A2A6C", "text_color": "#EAF1F8", "label": "Local Laplacian contrast/detail enhancement with strong edge preservation."},
|
|
|
|
{"after": "levels", "name": "rasterix_analog_film", "title": "🎞 Creative: Analog Film / CCD", "color": "#273C75", "text_color": "#EAF1F8", "label": "Stylized film and sensor-era rendering for mood, palette, and texture character. Inspired by DxO."},
|
|
{"after": "expiration_years", "name": "rasterix_photo_paper", "title": "🧪 Creative: Photo Paper Simulation", "color": "#273C75", "text_color": "#EAF1F8", "label": "Darkroom-inspired paper response with selectable grade, RC/FB base, color/B&W mode, and controlled print intensity."},
|
|
{"after": "paper_intensity", "name": "rasterix_lut_reader", "title": "📷 Creative: LUT .cube Reader", "color": "#273C75", "text_color": "#EAF1F8", "label": "Load and blend LUT looks for fast creative direction and consistent show style. Inspired by Blackmagic DaVinci Resolve and DxO."},
|
|
{"after": "color_space", "name": "rasterix_filmic_camera", "title": "🎥 Creative: Filmic Camera Curve", "color": "#273C75", "text_color": "#EAF1F8", "label": "Camera-like highlight roll-off and tonal response for cinematic dynamic range behavior. Inspired by Adobe Camera Raw."},
|
|
|
|
{"after": "pivot", "name": "rasterix_selective_tone", "title": "🎛 Color: Selective Tone Zones", "color": "#34495E", "text_color": "#EAF1F8", "label": "Zone-based tonal pushes for highlights, midtones, shadows, and blacks. Inspired by DxO Photolab"},
|
|
{"after": "selective_tone_strength", "name": "rasterix_color_balance", "title": "⚖ Color: Balance Wheels", "color": "#34495E", "text_color": "#EAF1F8", "label": "Color-balance style adjustments per tonal range with luminosity preservation options. Inspired by DaVinci Resolve and Photoshop color wheels."},
|
|
{"after": "color_balance_separation", "name": "rasterix_hsl", "title": "🌈 Color: HSL Sculpting", "color": "#34495E", "text_color": "#EAF1F8", "label": "Hue, saturation, lightness, and vibrance targeting by color channel. Inspired by Adobe Lightroom and Photoshop HSL panel."},
|
|
|
|
{"after": "hsl_skin_protection", "name": "rasterix_shade_detailer", "title": "💎 Detail: Microcontrast", "color": "#30336B", "text_color": "#EAF1F8", "label": "Fine local contrast shaping to emphasize texture and perceived detail. Inspired by DxO PhotoLab microcontrast tools."},
|
|
{"after": "shade_strength", "name": "rasterix_clarity", "title": "🔍 Detail: Midtone Clarity", "color": "#30336B", "text_color": "#EAF1F8", "label": "Midtone-focused clarity enhancement for crispness without excessive global contrast. Inspired by Adobe Lightroom Clarity."},
|
|
|
|
{"after": "edge_preservation", "name": "rasterix_endpoints", "title": "🔛 Output: Black/White Endpoints", "color": "#130F40", "text_color": "#EAF1F8", "label": "Set endpoint compression and clipping behavior for final output anchoring. Inspired by Adobe Photoshop Levels."},
|
|
{"after": "skip_if_no_clip", "name": "rasterix_dithering", "title": "🧩 Output: Dithering & Diffusion", "color": "#130F40", "text_color": "#EAF1F8", "label": "Reduce banding and smooth gradients using dither and error diffusion tools. Inspired by Floyd-Steinberg error diffusion."},
|
|
|
|
{"after": "error_diffusion", "name": "rasterix_histogram", "title": "📊 Analysis: Histogram", "color": "#0C2461", "text_color": "#EAF1F8", "label": "View channel histograms for fast clipping, balance, and tonal distribution checks. Inspired by Adobe Photoshop (and all other) Histogram."},
|
|
]
|
|
|
|
@classmethod
|
|
def _list_luts(cls):
|
|
lut_entries = ["None"]
|
|
if not os.path.exists(cls.LUT_DIR):
|
|
return lut_entries
|
|
|
|
for f in sorted(os.listdir(cls.LUT_DIR)):
|
|
full_path = os.path.join(cls.LUT_DIR, f)
|
|
if os.path.isfile(full_path) and f.lower().endswith(".cube"):
|
|
lut_entries.append(f)
|
|
|
|
for d in sorted(os.listdir(cls.LUT_DIR)):
|
|
subdir = os.path.join(cls.LUT_DIR, d)
|
|
if os.path.isdir(subdir):
|
|
for f in sorted(os.listdir(subdir)):
|
|
if f.lower().endswith(".cube"):
|
|
lut_entries.append(f"{d}/{f}")
|
|
|
|
return lut_entries
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"concepts": (["Auto"] + cls.CONCEPT_LIST,),
|
|
"models": (["Auto"] + cls.MODELLIST,),
|
|
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
|
|
"auto_normalize": ("BOOLEAN", {"default": False, "label_off": "No auto levels", "label_on": "Apply auto levels"}),
|
|
"auto_levels_threshold": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 10.0, "step": 0.1}),
|
|
"auto_gamma": ("BOOLEAN", {"default": False, "label_on": "Auto gamma: ON", "label_off": "Auto gamma:: OFF"}),
|
|
"gamma_target": ("FLOAT", {"default": 128.0, "min": 0.0, "max": 255.0, "step": 0.1}),
|
|
|
|
"use_white_balance": ("BOOLEAN", {"default": False, "label_off": "Ignore white balance", "label_on": "Apply white balance"}),
|
|
"wb_temperature": ("FLOAT", {"default": 6500, "min": 2000, "max": 12000, "step": 100}),
|
|
"wb_tint": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
|
|
"use_smart_lighting": ("BOOLEAN", {"default": False, "label_off": "Ignore smart lightning", "label_on": "Apply smart lightning"}),
|
|
"smart_lighting": ("FLOAT", {"default": 0, "min": 0, "max": 100, "step": 1}),
|
|
|
|
"use_dehaze": ("BOOLEAN", {"default": False, "label_off": "Ignore dehaze", "label_on": "Apply dehaze"}),
|
|
"strength": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 2.0, "step": 0.01}),
|
|
"dehaze_radius": ("INT", {"default": 15, "min": 3, "max": 100, "step": 1}),
|
|
"omega": ("FLOAT", {"default": 0.95, "min": 0.5, "max": 1.0, "step": 0.01}),
|
|
"t0": ("FLOAT", {"default": 0.1, "min": 0.01, "max": 0.5, "step": 0.01}),
|
|
"dehaze_contrast": ("FLOAT", {"default": 1.05, "min": 0.5, "max": 2.0, "step": 0.01}),
|
|
|
|
"use_depth_blur": ("BOOLEAN", {"default": False, "label_off": "Ignore depth blur", "label_on": "Apply depth blur"}),
|
|
"auto_optimize": ("BOOLEAN", {"default": False, "label_off": "Use custom inputs", "label_on": "Optimize settings by focus"}),
|
|
"use_DA_v3": ("BOOLEAN", {"default": False, "label_off": "Depth-anything V2", "label_on": "Depth-anything V3"}),
|
|
"DA_model": (["small", "base", "large", "mono", "metric", "giant", "nested"], {"default": "large"}),
|
|
"focus_depth": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"depth_range": ("FLOAT", {"default": 0.200, "min": 0.001, "max": 1.000, "step": 0.001}),
|
|
"max_blur": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 50.0, "step": 0.5}),
|
|
"depth_gamma": ("FLOAT", {"default": 1.00, "min": 0.10, "max": 5.00, "step": 0.01}),
|
|
|
|
"use_blur": ("BOOLEAN", {"default": False, "label_off": "Ignore blur", "label_on": "Apply blur"}),
|
|
"blur_type": (["gaussian", "box", "motion", "bilateral", "lens"], {"default": "bilateral"}),
|
|
"blur_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.1}),
|
|
"blur_radius": ("FLOAT", {"default": 2.0, "min": 0.5, "max": 50.0, "step": 0.5}),
|
|
"angle": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 360.0, "step": 1.0}),
|
|
"bilateral_edge_sensitivity": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"blur_edge_only": ("BOOLEAN", {"default": False, "label_off": "Full image blur", "label_on": "Flat areas only, edges protected"}),
|
|
"edge_threshold": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_brightness_contrast": ("BOOLEAN", {"default": False, "label_off": "Ignore brightness-contrast", "label_on": "Apply brightness-contrast"}),
|
|
"brightness": ("FLOAT", {"default": 0, "min": -150, "max": 150, "step": 1}),
|
|
"contrast": ("FLOAT", {"default": 0, "min": -50, "max": 100, "step": 1}),
|
|
"use_legacy": ("BOOLEAN", {"default": False, "label_off": "Use non-linear shift", "label_on": "Use adaptive offset"}),
|
|
|
|
"use_frequency_separation": ("BOOLEAN", {"default": False, "label_off": "Ignore frequency separation", "label_on": "Apply frequency separation"}),
|
|
"radius": ("FLOAT", {"default": 3.0, "min": 0.5, "max": 20.0, "step": 0.1}),
|
|
"low_freq_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
|
|
"high_freq_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
|
|
"blend_mode": (["add", "multiply", "overlay"], {"default": "add"}),
|
|
|
|
"use_local_laplacian": ("BOOLEAN", {"default": False, "label_off": "Ignore local laplacian", "label_on": "Apply local laplacian"}),
|
|
"sigma": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 5.0, "step": 0.1}),
|
|
"laplacian_contrast": ("FLOAT", {"default": 1.2, "min": 0.5, "max": 3.0, "step": 0.01}),
|
|
"detail": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
|
|
"levels": ("INT", {"default": 8, "min": 4, "max": 32, "step": 1}),
|
|
|
|
"use_film_rendering": ("BOOLEAN", {"default": False, "label_off": "Ignore film rendering", "label_on": "Apply film rendering"}),
|
|
"film_type": (cls.FILM_TYPES, {"default": "All"}),
|
|
"film_rendering": (list(FILM_PRESETS.keys()), {"default": list(FILM_PRESETS.keys())[0]}),
|
|
"film_rendering_intensity": ("FLOAT", {"default": 100, "min": 0, "max": 200, "step": 1}),
|
|
"iso_grain": ("BOOLEAN", {"default": False, "label_off": "Ignore ISO grain", "label_on": "Add ISO grain"}),
|
|
"halation": ("BOOLEAN", {"default": False, "label_off": "Ignore halation", "label_on": "Add halation"}),
|
|
"expiration_years": ("INT", {"default": 0, "min": 0, "max": 30, "step": 1}),
|
|
|
|
"use_photo_paper": ("BOOLEAN", {"default": False, "label_off": "Ignore photo paper", "label_on": "Apply photo paper"}),
|
|
"photo_paper": (list(PAPER_PRESETS.keys()), {"default": list(PAPER_PRESETS.keys())[0]}),
|
|
"color_paper": ("BOOLEAN", {"default": False, "label_off": "B&W paper", "label_on": "Color paper"}),
|
|
"paper_base": (["RC", "FB"], {"default": "RC"}),
|
|
"paper_expiration_years": ("FLOAT", {"default": 0, "min": 0, "max": 30, "step": 0.1}),
|
|
"paper_intensity": ("FLOAT", {"default": 100, "min": 0, "max": 200, "step": 1}),
|
|
|
|
"use_lut": ("BOOLEAN", {"default": False, "label_off": "Ignore LUT", "label_on": "Apply LUT"}),
|
|
"lut_file": (cls._list_luts(),),
|
|
"intensity": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}),
|
|
"color_space": (["sRGB", "linear"], {"default": "sRGB"}),
|
|
|
|
"use_filmic": ("BOOLEAN", {"default": False, "label_off": "Ignore filmic", "label_on": "Apply filmic"}),
|
|
"curve_type": (["filmic", "log"], {"default": "filmic"}),
|
|
"filmic_contrast": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 2.0, "step": 0.01}),
|
|
"highlight_rolloff": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"shadow_lift": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 0.5, "step": 0.01}),
|
|
"pivot": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_selective_tone": ("BOOLEAN", {"default": False, "label_off": "Ignore selective tone", "label_on": "Apply selective tone"}),
|
|
"selective_tone_value": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"selective_tone_zone": (["highlights", "midtones", "shadows", "blacks"], {"default": "midtones"}),
|
|
"selective_tone_separation": ("FLOAT", {"default": 50, "min": 0, "max": 100, "step": 1}),
|
|
"selective_tone_strength": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_color_balance": ("BOOLEAN", {"default": False, "label_off": "Ignore color balance", "label_on": "Apply color balance"}),
|
|
"color_balance_cyan_red": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"color_balance_magenta_green": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"color_balance_yellow_blue": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"color_balance_tone": (["highlights", "midtones", "shadows"], {"default": "midtones"}),
|
|
"color_balance_preserve_luminosity": ("BOOLEAN", {"default": False, "label_off": "Modify luminosity", "label_on": "Restore original luminosity"}),
|
|
"color_balance_separation": ("FLOAT", {"default": 50, "min": 0, "max": 100, "step": 1}),
|
|
|
|
"use_hsl": ("BOOLEAN", {"default": False, "label_off": "Ignore HSL", "label_on": "Apply HSL"}),
|
|
"hsl_hue": ("FLOAT", {"default": 0, "min": -180, "max": 180, "step": 1}),
|
|
"hsl_saturation": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"hsl_lightness": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"hsl_vibrance": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"hsl_channel": (["master", "red", "green", "blue"], {"default": "master"}),
|
|
"hsl_channel_width": ("FLOAT", {"default": 50, "min": 0, "max": 100, "step": 1}),
|
|
"hsl_skin_protection": ("BOOLEAN", {"default": True, "label_off": "Vibrance affects skin tones", "label_on": "Skin tones protected from vibrance"}),
|
|
|
|
"use_shade_detailer": ("BOOLEAN", {"default": False, "label_off": "Ignore shade detailer", "label_on": "Apply shade detailer"}),
|
|
"shade_level": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"shade_radius": ("FLOAT", {"default": 0, "min": 0, "max": 50, "step": 0.5}),
|
|
"detail_mode": (["fine", "medium", "broad"], {"default": "medium"}),
|
|
"shade_strength": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_clarity": ("BOOLEAN", {"default": False, "label_off": "Ignore clarity", "label_on": "Apply clarity"}),
|
|
"clarity_strength": ("FLOAT", {"default": 0.5, "min": -2.0, "max": 3.0, "step": 0.01}),
|
|
"clarity_radius": ("FLOAT", {"default": 2.0, "min": 0.5, "max": 10.0, "step": 0.1}),
|
|
"midtone_range": ("FLOAT", {"default": 0.5, "min": 0.1, "max": 1.0, "step": 0.01}),
|
|
"edge_preservation": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_level_endpoints": ("BOOLEAN", {"default": False, "label_off": "Ignore endpoint offset", "label_on": "Apply endpoint offset"}),
|
|
"black_offset": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 25.0, "step": 0.1}),
|
|
"white_offset": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 25.0, "step": 0.1}),
|
|
"skip_if_no_clip": ("BOOLEAN", {"default": False, "label_off": "Offset all values", "label_on": "Skip if no clips"}),
|
|
|
|
"normalize_gaps": ("BOOLEAN", {"default": False, "label_on": "Anti-comb filter: ON", "label_off": "Anti-comb filter: OFF"}),
|
|
"normalize_midpeaks": ("BOOLEAN", {"default": False, "label_on": "Anti-spike filter: ON", "label_off": "Anti-spike filter: OFF"}),
|
|
"peak_width": ("INT", {"default": 3, "min": 1, "max": 10, "step": 1}),
|
|
"dither_quantization": ("BOOLEAN", {"default": False, "label_off": "Dither quantization OFF", "label_on": "Dither quantization ON"}),
|
|
"adaptive_dither_strength": ("BOOLEAN", {"default": False, "label_off": "Keep dither strength", "label_on": "Increase dither strength"}),
|
|
"error_diffusion": ("BOOLEAN", {"default": False, "label_off": "Error diffusion OFF", "label_on": "Error diffusion ON"}),
|
|
|
|
"show_histogram": ("BOOLEAN", {"default": False, "label_off": "Ignore histogram", "label_on": "Create histogram"}),
|
|
"histogram_source": ("BOOLEAN", {"default": False, "label_off": "Show output histogram", "label_on": "Show input histogram"}),
|
|
"histogram_channel": (["RGB", "RED", "GREEN", "BLUE"], {"default": "RGB"}),
|
|
"histogram_style": (["bars", "lines", "waveform", "heatmap", "stacked", "luma", "parade", "gradient", "glow", "dots", "step", "log", "percentile", "inverse"], {"default": "bars"}),
|
|
},
|
|
"optional": {
|
|
"model_concept": ("STRING", {"default": None, "forceInput": True}),
|
|
"model_name": ("CHECKPOINT_NAME", {"default": None, "forceInput": True}),
|
|
"seed": ("INT", {"default": 0, "min": 0, "max": utility.MAX_SEED, "forceInput": True}),
|
|
},
|
|
"hidden": {
|
|
"id": "UNIQUE_ID",
|
|
}
|
|
}
|
|
|
|
def primere_rasterix(self, **kwargs):
|
|
concepts = kwargs.get('concepts', 'Auto')
|
|
models = kwargs.get('models', 'Auto')
|
|
model_concept = kwargs.get('model_concept', None)
|
|
model_name = kwargs.get('model_name', None)
|
|
seed = kwargs.get('seed', 0)
|
|
active_concept = model_concept if concepts == "Auto" else concepts
|
|
active_display = active_concept
|
|
|
|
auto_runtime_mode = concepts == "Auto" and models == "Auto"
|
|
|
|
if auto_runtime_mode:
|
|
raw_model = model_name
|
|
model_key = os.path.splitext(os.path.basename(raw_model))[0] if raw_model else None
|
|
json_path = os.path.join(PRIMERE_ROOT, 'front_end', 'rasterix_settings.json')
|
|
concept_data = utility.json2tuple(json_path)
|
|
if model_key and concept_data and model_key in concept_data:
|
|
lookup_key = model_key
|
|
active_display = model_key
|
|
else:
|
|
lookup_key = active_concept
|
|
active_display = active_concept
|
|
if not concept_data or lookup_key not in concept_data:
|
|
PromptServer.instance.send_sync("primere.rasterix_setting", {"status": "missing", "concept": active_concept})
|
|
else:
|
|
saved = concept_data[lookup_key]
|
|
for k, v in saved.items():
|
|
if k in kwargs:
|
|
kwargs[k] = v
|
|
|
|
p = SimpleNamespace(**kwargs)
|
|
node_id = p.id
|
|
|
|
pil_img = utility.tensor_to_image(p.image)
|
|
pil_img_input = pil_img.copy()
|
|
|
|
rasterix_json_path = os.path.join(PRIMERE_ROOT, 'front_end', 'rasterix.json')
|
|
rasterix_data = utility.json2tuple(rasterix_json_path) or {}
|
|
|
|
if p.auto_normalize:
|
|
pil_img = img_levels_auto.img_levels_auto(image=pil_img, auto_normalize=p.auto_normalize, threshold=p.auto_levels_threshold, normalize_gaps=p.normalize_gaps, normalize_midpeaks=False, peak_width=p.peak_width, auto_gamma=p.auto_gamma, gamma_target=p.gamma_target, precision=p.precision, seed=seed)
|
|
|
|
if p.use_white_balance and (p.wb_temperature != 6500 or p.wb_tint != 0):
|
|
pil_img = img_white_balance.img_white_balance(image=pil_img, temperature=p.wb_temperature, tint=p.wb_tint)
|
|
|
|
if p.use_smart_lighting and p.smart_lighting != 0:
|
|
pil_img = img_smart_lighting.img_smart_lighting(image=pil_img, intensity=p.smart_lighting)
|
|
|
|
if p.use_dehaze and p.strength > 0:
|
|
pil_img = img_dehaze.img_dehaze(image=pil_img, strength=p.strength, radius=p.dehaze_radius, omega=p.omega, t0=p.t0, contrast=p.dehaze_contrast, precision=p.precision)
|
|
|
|
if p.use_depth_blur and p.focus_depth > 0 and p.max_blur > 0:
|
|
pil_img = img_depth_blur.img_depth_blur(image=pil_img, focus_depth=p.focus_depth, depth_range=p.depth_range, max_blur=p.max_blur, depth_gamma=p.depth_gamma, auto_optimize=p.auto_optimize, use_v3=p.use_DA_v3, DA_model=p.DA_model)
|
|
|
|
if p.use_blur and p.blur_intensity != 0:
|
|
pil_img = img_blur.img_blur(image=pil_img, blur_type=p.blur_type, intensity=p.blur_intensity, radius=p.blur_radius, angle=p.angle, edge_only=p.blur_edge_only, bilateral_edge_sensitivity=p.bilateral_edge_sensitivity, edge_threshold=p.edge_threshold)
|
|
|
|
if p.use_brightness_contrast and (p.brightness != 0 or p.contrast != 0):
|
|
pil_img = img_brightness_contrast.img_brightness_contrast(image=pil_img, brightness=p.brightness, contrast=p.contrast, use_legacy=p.use_legacy)
|
|
|
|
if p.use_frequency_separation:
|
|
pil_img = img_frequency_separation.img_frequency_separation(image=pil_img, radius=p.radius, low_freq_strength=p.low_freq_strength, high_freq_strength=p.high_freq_strength, blend_mode=p.blend_mode)
|
|
|
|
if p.use_local_laplacian:
|
|
pil_img = img_local_laplacian.img_local_laplacian(image=pil_img, sigma=p.sigma, contrast=p.laplacian_contrast, detail=p.detail, levels=p.levels)
|
|
|
|
film_rendering = p.film_rendering
|
|
if p.film_type != "All":
|
|
allowed_presets = self.FILM_PRESETS_BY_TYPE.get(p.film_type, [])
|
|
if allowed_presets and p.film_rendering not in allowed_presets:
|
|
film_rendering = allowed_presets[0]
|
|
if p.use_film_rendering and p.film_rendering_intensity != 0:
|
|
pil_img = img_film_rendering.img_film_rendering(image=pil_img, rendering=film_rendering, intensity=p.film_rendering_intensity, add_grain=p.iso_grain, add_halation=p.halation, expiration_years=p.expiration_years)
|
|
|
|
if p.use_lut and p.lut_file != "None":
|
|
lut_path = os.path.join(self.LUT_DIR, p.lut_file)
|
|
pil_img = img_lut3d.img_lut3d(image=pil_img, lut_path=lut_path, intensity=p.intensity, input_space=p.color_space, output_space=p.color_space)
|
|
|
|
if p.use_filmic:
|
|
pil_img = img_filmic_curve.img_filmic_curve(image=pil_img, curve_type=p.curve_type, contrast=p.filmic_contrast, highlight_rolloff=p.highlight_rolloff, shadow_lift=p.shadow_lift, pivot=p.pivot)
|
|
|
|
if p.use_photo_paper and p.paper_intensity != 0:
|
|
pil_img = img_photo_paper.img_photo_paper(image=pil_img, paper_type=p.photo_paper, color_paper=p.color_paper, paper_base=p.paper_base, paper_intensity=p.paper_intensity, expiration_years=p.paper_expiration_years)
|
|
|
|
st_data = rasterix_data.get('selective_tone', {})
|
|
if p.use_selective_tone and st_data:
|
|
pil_img = img_selective_tone.img_selective_tone(image=pil_img, channels_data=st_data, separation=p.selective_tone_separation, strength=p.selective_tone_strength)
|
|
|
|
cb_data = rasterix_data.get('color_balance', {})
|
|
if p.use_color_balance and cb_data:
|
|
pil_img = img_color_balance.img_color_balance(image=pil_img, channels_data=cb_data, preserve_luminosity=p.color_balance_preserve_luminosity, separation=p.color_balance_separation)
|
|
|
|
hs_data = rasterix_data.get('hue_saturation', {})
|
|
if p.use_hsl and hs_data:
|
|
pil_img = img_hue_saturation.img_hue_saturation(image=pil_img, channels_data=hs_data, channel_width=p.hsl_channel_width, skin_protection=p.hsl_skin_protection)
|
|
|
|
shade_data = rasterix_data.get('shade', {})
|
|
if p.use_shade_detailer and shade_data:
|
|
for mode, vals in shade_data.items():
|
|
lvl = vals.get('shade_level', 0)
|
|
if lvl != 0:
|
|
rad = vals.get('shade_radius', 0)
|
|
pil_img = img_shade_level.img_shade_level(image=pil_img, shade_level=lvl, radius=rad, strength=p.shade_strength)
|
|
|
|
if p.use_clarity and p.strength != 0:
|
|
pil_img = img_clarity.img_clarity(image=pil_img, strength=p.clarity_strength, radius=p.clarity_radius, midtone_range=p.midtone_range, edge_preservation=p.edge_preservation, precision=p.precision)
|
|
|
|
if p.use_level_endpoints and (p.black_offset != 0 or p.white_offset != 0):
|
|
pil_img = img_levels_compress.img_levels_compress(image=pil_img, black_offset=p.black_offset, white_offset=p.white_offset, skip_if_no_clip=p.skip_if_no_clip, high_precision=p.precision)
|
|
|
|
if p.dither_quantization or p.error_diffusion or p.normalize_midpeaks:
|
|
pil_img = img_dithering.img_dithering(image=pil_img, dither_quantization=p.dither_quantization, adaptive_dither_strength=p.adaptive_dither_strength, error_diffusion=p.error_diffusion, normalize_midpeaks=p.normalize_midpeaks, peak_width=p.peak_width, high_precision=p.precision, seed=seed)
|
|
|
|
histogram.rasterix_hist_cache_store(pil_img_input, pil_img, p.precision, node_id=node_id)
|
|
if p.show_histogram:
|
|
histogram.rasterix_hist_cache_store(pil_img_input, pil_img, p.precision, node_id=node_id)
|
|
active_hist = histogram.rasterix_hist_render_selected(pil_img_input, pil_img, p.precision, p.histogram_source, p.histogram_channel, p.histogram_style, node_id=node_id)
|
|
suffix = ''.join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for _ in range(8))
|
|
temp_file = f"rasterix_hist_{suffix}.png"
|
|
active_hist.save(os.path.join(folder_paths.temp_directory, temp_file), compress_level=1)
|
|
return {"ui": {"images": [{"filename": temp_file, "subfolder": "", "type": "temp"}], "active_concept": [active_display]}, "result": (utility.image_to_tensor(pil_img),), }
|
|
else:
|
|
INVALID_IMAGE_PATH = os.path.join(PRIMERE_ROOT, 'front_end', 'images')
|
|
INVALID_IMAGE = os.path.join(INVALID_IMAGE_PATH, "No_histogram_08.jpg")
|
|
images = utility.ImageLoaderFromPath(INVALID_IMAGE)
|
|
r1 = random.randint(1000, 9999)
|
|
temp_filename = f"Primere_ComfyUI_{r1}.png"
|
|
os.makedirs(folder_paths.get_temp_directory(), exist_ok=True)
|
|
TEMP_FILE = os.path.join(folder_paths.get_temp_directory(), temp_filename)
|
|
utility.tensor_to_image(images[0]).save(TEMP_FILE)
|
|
return {"ui": {"images": [{"filename": temp_filename, "subfolder": "", "type": "temp"}], "active_concept": [active_display]}, "result": (utility.image_to_tensor(pil_img),),}
|
|
|
|
class PrimereAutoNormalize:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_auto_normalize"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
"auto_normalize": ("BOOLEAN", {"default": False, "label_off": "No auto levels", "label_on": "Apply auto levels"}),
|
|
"auto_levels_threshold": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 10.0, "step": 0.1}),
|
|
"auto_gamma": ("BOOLEAN", {"default": False, "label_on": "Auto gamma: ON", "label_off": "Auto gamma:: OFF"}),
|
|
"gamma_target": ("FLOAT", {"default": 128.0, "min": 0.0, "max": 255.0, "step": 0.1}),
|
|
"normalize_gaps": ("BOOLEAN", {"default": False, "label_on": "Anti-comb filter: ON", "label_off": "Anti-comb filter: OFF"}),
|
|
"normalize_midpeaks": ("BOOLEAN", {"default": False, "label_on": "Anti-spike filter: ON", "label_off": "Anti-spike filter: OFF"}),
|
|
"peak_width": ("INT", {"default": 3, "min": 1, "max": 10, "step": 1}),
|
|
},
|
|
"optional": {
|
|
"seed": ("INT", {"default": 0, "min": 0, "max": utility.MAX_SEED, "forceInput": True}),
|
|
}
|
|
}
|
|
|
|
def primere_auto_normalize(self, image, precision, auto_normalize, auto_levels_threshold, auto_gamma, gamma_target, normalize_gaps, normalize_midpeaks, peak_width, seed = None):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if auto_normalize:
|
|
pil_img = img_levels_auto.img_levels_auto(image=pil_img, auto_normalize=auto_normalize, threshold=auto_levels_threshold, normalize_gaps=normalize_gaps, normalize_midpeaks=normalize_midpeaks, peak_width=peak_width, auto_gamma=auto_gamma, gamma_target=gamma_target, precision=precision, seed=seed)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereWhiteBalance:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_white_balance"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_white_balance": ("BOOLEAN", {"default": False, "label_off": "Ignore white balance", "label_on": "Apply white balance"}),
|
|
"wb_temperature": ("FLOAT", {"default": 6500, "min": 2000, "max": 12000, "step": 100}),
|
|
"wb_tint": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
}
|
|
}
|
|
|
|
def primere_white_balance(self, image, use_white_balance, wb_temperature, wb_tint):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_white_balance and (wb_temperature != 6500 or wb_tint != 0):
|
|
pil_img = img_white_balance.img_white_balance(image=pil_img, temperature=wb_temperature, tint=wb_tint)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereSmartLighting:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_smart_lighting"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_smart_lighting": ("BOOLEAN", {"default": False, "label_off": "Ignore smart lightning", "label_on": "Apply smart lightning"}),
|
|
"smart_lighting": ("FLOAT", {"default": 0, "min": 0, "max": 100, "step": 1}),
|
|
}
|
|
}
|
|
|
|
def primere_smart_lighting(self, image, use_smart_lighting, smart_lighting):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_smart_lighting and smart_lighting != 0:
|
|
pil_img = img_smart_lighting.img_smart_lighting(image=pil_img, intensity=smart_lighting)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereBlur:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_blur"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_blur": ("BOOLEAN", {"default": False, "label_off": "Ignore blur", "label_on": "Apply blur"}),
|
|
"blur_type": (["gaussian", "box", "motion", "bilateral", "lens"], {"default": "bilateral"}),
|
|
"blur_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 5.0, "step": 0.1}),
|
|
"blur_radius": ("FLOAT", {"default": 2.0, "min": 0.5, "max": 50.0, "step": 0.5}),
|
|
"angle": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 360.0, "step": 1.0}),
|
|
"bilateral_edge_sensitivity": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"blur_edge_only": ("BOOLEAN", {"default": False, "label_off": "Full image blur", "label_on": "Flat areas only, edges protected"}),
|
|
"edge_threshold": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_blur(self, image, use_blur, blur_type, blur_intensity, blur_radius, angle, bilateral_edge_sensitivity, blur_edge_only, edge_threshold):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_blur and blur_intensity != 0:
|
|
pil_img = img_blur.img_blur(image=pil_img, blur_type=blur_type, intensity=blur_intensity, radius=blur_radius, angle=angle, edge_only=blur_edge_only, bilateral_edge_sensitivity=bilateral_edge_sensitivity, edge_threshold=edge_threshold)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereBrightnessContrast:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_brightness_contrast"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_brightness_contrast": ("BOOLEAN", {"default": False, "label_off": "Ignore brightness-contrast", "label_on": "Apply brightness-contrast"}),
|
|
"brightness": ("FLOAT", {"default": 0, "min": -150, "max": 150, "step": 1}),
|
|
"contrast": ("FLOAT", {"default": 0, "min": -50, "max": 100, "step": 1}),
|
|
"use_legacy": ("BOOLEAN", {"default": False, "label_off": "Use non-linear shift", "label_on": "Use adaptive offset"}),
|
|
}
|
|
}
|
|
|
|
def primere_brightness_contrast(self, image, use_brightness_contrast, brightness, contrast, use_legacy):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_brightness_contrast and (brightness != 0 or contrast != 0):
|
|
pil_img = img_brightness_contrast.img_brightness_contrast(image=pil_img, brightness=brightness, contrast=contrast, use_legacy=use_legacy)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereFilmRendering:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_film_rendering"
|
|
CATEGORY = TREE_RASTERIX
|
|
FILM_TYPES = ["All", "CF", "BWF", "CCD", "MOB"]
|
|
FILM_PRESETS_BY_TYPE = img_film_rendering.list_presets_by_type()
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_film_rendering": ("BOOLEAN", {"default": False, "label_off": "Ignore film rendering", "label_on": "Apply film rendering"}),
|
|
"film_type": (cls.FILM_TYPES, {"default": "All"}),
|
|
"film_rendering": (list(FILM_PRESETS.keys()), {"default": list(FILM_PRESETS.keys())[0]}),
|
|
"film_rendering_intensity": ("FLOAT", {"default": 100, "min": 0, "max": 200, "step": 1}),
|
|
"iso_grain": ("BOOLEAN", {"default": False, "label_off": "Ignore ISO grain", "label_on": "Add ISO grain"}),
|
|
"halation": ("BOOLEAN", {"default": False, "label_off": "Ignore halation", "label_on": "Add halation"}),
|
|
"expiration_years": ("INT", {"default": 0, "min": 0, "max": 30, "step": 1}),
|
|
}
|
|
}
|
|
|
|
def primere_film_rendering(self, image, film_type, use_film_rendering, film_rendering, film_rendering_intensity, iso_grain, halation, expiration_years):
|
|
pil_img = utility.tensor_to_image(image)
|
|
|
|
if film_type != "All":
|
|
allowed_presets = self.FILM_PRESETS_BY_TYPE.get(film_type, [])
|
|
if allowed_presets and film_rendering not in allowed_presets:
|
|
film_rendering = allowed_presets[0]
|
|
|
|
if use_film_rendering and film_rendering_intensity != 0:
|
|
pil_img = img_film_rendering.img_film_rendering(image=pil_img, rendering=film_rendering, intensity=film_rendering_intensity, add_grain=iso_grain, add_halation=halation, expiration_years=expiration_years)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereSelectiveTone:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_selective_tone"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_selective_tone": ("BOOLEAN", {"default": False, "label_off": "Ignore selective tone", "label_on": "Apply selective tone"}),
|
|
"selective_tone_value": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"selective_tone_zone": (["highlights", "midtones", "shadows", "blacks"], {"default": "midtones"}),
|
|
"selective_tone_separation": ("FLOAT", {"default": 50, "min": 0, "max": 100, "step": 1}),
|
|
"selective_tone_strength": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_selective_tone(self, image, use_selective_tone, selective_tone_value, selective_tone_zone, selective_tone_separation, selective_tone_strength):
|
|
pil_img = utility.tensor_to_image(image)
|
|
rasterix_json_path = os.path.join(PRIMERE_ROOT, 'front_end', 'rasterix.json')
|
|
rasterix_data = utility.json2tuple(rasterix_json_path) or {}
|
|
st_data = rasterix_data.get('selective_tone', {})
|
|
if use_selective_tone and st_data:
|
|
pil_img = img_selective_tone.img_selective_tone(image=pil_img, channels_data=st_data, separation=selective_tone_separation, strength=selective_tone_strength)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereColorBalance:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_color_balance"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_color_balance": ("BOOLEAN", {"default": False, "label_off": "Ignore color balance", "label_on": "Apply color balance"}),
|
|
"color_balance_cyan_red": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"color_balance_magenta_green": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"color_balance_yellow_blue": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"color_balance_tone": (["highlights", "midtones", "shadows"], {"default": "midtones"}),
|
|
"color_balance_preserve_luminosity": ("BOOLEAN", {"default": False, "label_off": "Modify luminosity", "label_on": "Restore original luminosity"}),
|
|
"color_balance_separation": ("FLOAT", {"default": 50, "min": 0, "max": 100, "step": 1}),
|
|
}
|
|
}
|
|
|
|
def primere_color_balance(self, image, use_color_balance, color_balance_cyan_red, color_balance_magenta_green, color_balance_yellow_blue, color_balance_tone, color_balance_preserve_luminosity, color_balance_separation):
|
|
pil_img = utility.tensor_to_image(image)
|
|
rasterix_json_path = os.path.join(PRIMERE_ROOT, 'front_end', 'rasterix.json')
|
|
rasterix_data = utility.json2tuple(rasterix_json_path) or {}
|
|
cb_data = rasterix_data.get('color_balance', {})
|
|
if use_color_balance and cb_data:
|
|
pil_img = img_color_balance.img_color_balance(image=pil_img, channels_data=cb_data, preserve_luminosity=color_balance_preserve_luminosity, separation=color_balance_separation)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereHSL:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_hsl"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_hsl": ("BOOLEAN", {"default": False, "label_off": "Ignore HSL", "label_on": "Apply HSL"}),
|
|
"hsl_hue": ("FLOAT", {"default": 0, "min": -180, "max": 180, "step": 1}),
|
|
"hsl_saturation": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"hsl_lightness": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"hsl_vibrance": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"hsl_channel": (["master", "red", "green", "blue"], {"default": "master"}),
|
|
"hsl_channel_width": ("FLOAT", {"default": 50, "min": 0, "max": 100, "step": 1}),
|
|
"hsl_skin_protection": ("BOOLEAN", {"default": True, "label_off": "Vibrance affects skin tones", "label_on": "Skin tones protected from vibrance"}),
|
|
}
|
|
}
|
|
|
|
def primere_hsl(self, image, use_hsl, hsl_hue, hsl_saturation, hsl_lightness, hsl_vibrance, hsl_channel, hsl_channel_width, hsl_skin_protection):
|
|
pil_img = utility.tensor_to_image(image)
|
|
rasterix_json_path = os.path.join(PRIMERE_ROOT, 'front_end', 'rasterix.json')
|
|
rasterix_data = utility.json2tuple(rasterix_json_path) or {}
|
|
hs_data = rasterix_data.get('hue_saturation', {})
|
|
if use_hsl and hs_data:
|
|
pil_img = img_hue_saturation.img_hue_saturation(image=pil_img, channels_data=hs_data, channel_width=hsl_channel_width, skin_protection=hsl_skin_protection)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereShadeDetailer:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_shade_detailer"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_shade_detailer": ("BOOLEAN", {"default": False, "label_off": "Ignore shade detailer", "label_on": "Apply shade detailer"}),
|
|
"shade_level": ("FLOAT", {"default": 0, "min": -100, "max": 100, "step": 1}),
|
|
"shade_radius": ("FLOAT", {"default": 0, "min": 0, "max": 50, "step": 0.5}),
|
|
"detail_mode": (["fine", "medium", "broad"], {"default": "medium"}),
|
|
"shade_strength": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_shade_detailer(self, image, use_shade_detailer, shade_level, shade_radius, detail_mode, shade_strength):
|
|
pil_img = utility.tensor_to_image(image)
|
|
rasterix_json_path = os.path.join(PRIMERE_ROOT, 'front_end', 'rasterix.json')
|
|
rasterix_data = utility.json2tuple(rasterix_json_path) or {}
|
|
shade_data = rasterix_data.get('shade', {})
|
|
if use_shade_detailer and shade_data:
|
|
for mode, vals in shade_data.items():
|
|
lvl = vals.get('shade_level', 0)
|
|
if lvl != 0:
|
|
rad = vals.get('shade_radius', 0)
|
|
pil_img = img_shade_level.img_shade_level(image=pil_img, shade_level=lvl, radius=rad, strength=shade_strength)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereLevelEndpoints:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_level_endpoints"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
"use_level_endpoints": ("BOOLEAN", {"default": False, "label_off": "Ignore endpoint offset", "label_on": "Apply endpoint offset"}),
|
|
"black_offset": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 25.0, "step": 0.1}),
|
|
"white_offset": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 25.0, "step": 0.1}),
|
|
"skip_if_no_clip": ("BOOLEAN", {"default": False, "label_off": "Offset all values", "label_on": "Skip if no clips"}),
|
|
}
|
|
}
|
|
|
|
def primere_level_endpoints(self, image, precision, use_level_endpoints, black_offset, white_offset, skip_if_no_clip):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_level_endpoints and (black_offset != 0 or white_offset != 0):
|
|
pil_img = img_levels_compress.img_levels_compress(image=pil_img, black_offset=black_offset, white_offset=white_offset, skip_if_no_clip=skip_if_no_clip, high_precision=precision)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimerePosterize:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_posterize"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_posterize": ("BOOLEAN", {"default": False, "label_off": "Ignore posterize", "label_on": "Apply posterize"}),
|
|
"shades": ("INT", {"default": 255, "min": 1, "max": 255, "step": 1}),
|
|
"channels": (["Red", "Green", "Blue"], {"default": "Red"}),
|
|
}
|
|
}
|
|
|
|
def primere_posterize(self, image, use_posterize, shades, channels):
|
|
pil_img = utility.tensor_to_image(image)
|
|
rasterix_json_path = os.path.join(PRIMERE_ROOT, 'front_end', 'rasterix.json')
|
|
rasterix_data = utility.json2tuple(rasterix_json_path) or {}
|
|
poster_data = rasterix_data.get('posterize', {})
|
|
if use_posterize and poster_data:
|
|
pil_img = img_posterize.img_posterize(image=pil_img, channels_data=poster_data)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereDithering:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_dithering"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
"normalize_midpeaks": ("BOOLEAN", {"default": False, "label_on": "Anti-spike filter: ON", "label_off": "Anti-spike filter: OFF"}),
|
|
"peak_width": ("INT", {"default": 3, "min": 1, "max": 10, "step": 1}),
|
|
"dither_quantization": ("BOOLEAN", {"default": False, "label_off": "Dither quantization OFF", "label_on": "Dither quantization ON"}),
|
|
"adaptive_dither_strength": ("BOOLEAN", {"default": False, "label_off": "Keep dither strength", "label_on": "Increase dither strength"}),
|
|
"error_diffusion": ("BOOLEAN", {"default": False, "label_off": "Error diffusion OFF", "label_on": "Error diffusion ON"}),
|
|
}
|
|
}
|
|
|
|
def primere_dithering(self, image, precision, normalize_midpeaks, peak_width, dither_quantization, adaptive_dither_strength, error_diffusion):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if dither_quantization or error_diffusion or normalize_midpeaks:
|
|
pil_img = img_dithering.img_dithering(image=pil_img, dither_quantization=dither_quantization, adaptive_dither_strength=adaptive_dither_strength, error_diffusion=error_diffusion, normalize_midpeaks=normalize_midpeaks, peak_width=peak_width, high_precision=precision)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereAIDetectionBypasser:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_ai_detection_bypasser"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_ai_detection_bypasser": ("BOOLEAN", {"default": False, "label_off": "AI detection bypass off", "label_on": "AI detection bypass on"}),
|
|
"adb_freq_strength": ("FLOAT", {"default": 0.019, "min": 0.0, "max": 0.1, "step": 0.001}),
|
|
"adb_variance_strength": ("FLOAT", {"default": 0.32, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"adb_unsharp_percent": ("INT", {"default": 38, "min": 0, "max": 150, "step": 1}),
|
|
"adb_jpeg_cycles": ("INT", {"default": 4, "min": 0, "max": 6, "step": 1}),
|
|
}
|
|
}
|
|
|
|
def primere_ai_detection_bypasser(self, image, use_ai_detection_bypasser, adb_freq_strength, adb_variance_strength, adb_unsharp_percent, adb_jpeg_cycles):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_ai_detection_bypasser:
|
|
pil_img = isgen_detect_ext_full.bypass_ai_detector(image=pil_img, freq_strength=adb_freq_strength, variance_strength=adb_variance_strength, unsharp_percent=adb_unsharp_percent, jpeg_cycles=adb_jpeg_cycles)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereRasterixGrain:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_rasterix_grain"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
|
|
"use_grain": ("BOOLEAN", {"default": False, "label_off": "Ignore grain", "label_on": "Apply grain"}),
|
|
"intensity": ("FLOAT", {"default": 20.0, "min": 0.0, "max": 100.0, "step": 0.5}),
|
|
"grain_size": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 8.0, "step": 0.1}),
|
|
"grain_type": (["gaussian", "organic", "salt_pepper", "fine"], {"default": "gaussian"}),
|
|
"color_mode": (["color", "monochrome"], {"default": "color"}),
|
|
"color_tint": (["neutral", "warm", "cool", "green", "custom"], {"default": "neutral"}),
|
|
"color_tint_r": ("FLOAT", {"default": 0, "min": -50, "max": 50, "step": 1}),
|
|
"color_tint_g": ("FLOAT", {"default": 0, "min": -50, "max": 50, "step": 1}),
|
|
"color_tint_b": ("FLOAT", {"default": 0, "min": -50, "max": 50, "step": 1}),
|
|
"shadow_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.05}),
|
|
"highlight_strength": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 3.0, "step": 0.05}),
|
|
"midtone_peak": ("FLOAT", {"default": 0.4, "min": 0.0, "max": 1.0, "step": 0.05}),
|
|
"vignette_boost": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.05}),
|
|
},
|
|
"optional": {
|
|
"seed": ("INT", {"default": 0, "min": 0, "max": utility.MAX_SEED, "forceInput": True}),
|
|
}
|
|
}
|
|
|
|
def primere_rasterix_grain(self, image, use_grain, intensity, grain_size, grain_type, color_mode, color_tint, color_tint_r, color_tint_g, color_tint_b, shadow_strength, highlight_strength, midtone_peak, vignette_boost, seed=None):
|
|
if intensity == 0 or use_grain == False:
|
|
return (image,)
|
|
|
|
pil_img = utility.tensor_to_image(image)
|
|
pil_img = img_film_grain.img_film_grain(
|
|
image=pil_img,
|
|
intensity=intensity,
|
|
grain_size=grain_size,
|
|
grain_type=grain_type,
|
|
color_mode=color_mode,
|
|
color_tint=color_tint,
|
|
color_tint_rgb=(color_tint_r, color_tint_g, color_tint_b),
|
|
shadow_strength=shadow_strength,
|
|
highlight_strength=highlight_strength,
|
|
midtone_peak=midtone_peak,
|
|
vignette_boost=vignette_boost,
|
|
seed=seed,
|
|
)
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
|
|
class PrimereRasterixLens:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_rasterix_lens"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
SECTION_TITLES = [
|
|
# {"before": "lens_profile", "name": "lensfx_profile", "title": "📸 Real Lens Profile", "color": "#1B263B", "text_color": "#EAF1F8", "label": "Select a real camera lens to automatically load authentic optical characteristics (vignette, distortion, CA, flare, anamorphic, etc.). Fine-tune any slider afterwards."},
|
|
{"before": "use_vignette", "name": "lensfx_vignette", "title": "🌑 Vignette Control", "color": "#1B263B", "text_color": "#EAF1F8", "label": "Master toggle and parameters for vignette: darken corners/edges with strength, radius, feather, and shape. Inspired by Adobe Lightroom."},
|
|
{"before": "use_chroma", "name": "lensfx_chromatic", "title": "🌈 Chromatic Aberration", "color": "#243B55", "text_color": "#EAF1F8", "label": "Toggle and control chromatic aberration: intensity, falloff, and fringe color for realistic color fringing. Inspired by Adobe Camera Raw."},
|
|
{"before": "use_bokeh", "name": "lensfx_bokeh", "title": "✨ Bokeh Effect", "color": "#1A2A6C", "text_color": "#EAF1F8", "label": "Enable bokeh simulation: radius, blade count, highlight boost, and cat-eye shaping for dreamy out-of-focus highlights. Inspired by Adobe Photoshop."},
|
|
{"before": "use_distortion", "name": "lensfx_distortion", "title": "🌀 Lens Distortion", "color": "#0F3443", "text_color": "#EAF1F8", "label": "Toggle barrel/pincushion/zoom distortion: simulate classic lens imperfections with fine-grained controls. Inspired by DxO PhotoLab."},
|
|
{"before": "use_flare", "name": "lensfx_flare", "title": "☀️ Lens Flare", "color": "#273C75", "text_color": "#EAF1F8", "label": "Activate realistic lens flare: intensity, position, streak/ghost count, length, and color tinting. Inspired by Adobe Photoshop."},
|
|
{"before": "use_halation", "name": "lensfx_halation", "title": "🌟 Halation Glow", "color": "#34495E", "text_color": "#EAF1F8", "label": "Toggle halation: glow around bright areas with intensity, radius, threshold, and warmth adjustment. Inspired by Blackmagic DaVinci Resolve."},
|
|
{"before": "use_focus", "name": "lensfx_focus", "title": "🔍 Focus Falloff", "color": "#30336B", "text_color": "#EAF1F8", "label": "Enable selective focus blur: radius, mode (horizontal/vertical/radial/oval), position, width, and feather. Inspired by Adobe Photoshop."},
|
|
{"before": "use_spherical", "name": "lensfx_spherical", "title": "🌐 Spherical Aberration", "color": "#130F40", "text_color": "#EAF1F8", "label": "Toggle spherical aberration: intensity, radius, and zone (centre/edge/global) for soft-focus effects."},
|
|
{"before": "use_anamorphic", "name": "lensfx_anamorphic", "title": "📽️ Anamorphic Lens", "color": "#0C2461", "text_color": "#EAF1F8", "label": "Apply anamorphic characteristics: intensity, streak color/length, oval bokeh, and blue bias for cinematic look. Inspired by Blackmagic DaVinci Resolve."},
|
|
{"before": "use_coating_spectral", "name": "lensfx_coating_spectral", "title": "🔬 Coating & Spectral", "color": "#2C3E50", "text_color": "#EAF1F8", "label": "Lens coating quality and per-channel spectral response for film/sensor simulation."},
|
|
{"before": "use_advanced_aberrations", "name": "lensfx_advanced_aberrations", "title": "📐 Advanced Optical Aberrations", "color": "#34495E", "text_color": "#EAF1F8", "label": "Field curvature, astigmatism, coma, breathing, and anamorphic squeeze for realistic lens imperfections."},
|
|
{"before": "use_sensor_effects", "name": "lensfx_sensor_effects", "title": "📸 Sensor & Bloom Effects", "color": "#3D5A6B", "text_color": "#EAF1F8", "label": "Sensor bloom, glare, and microlens array simulation."},
|
|
{"before": "use_creative_effects", "name": "lensfx_creative_effects", "title": "✨ Creative Optical Effects", "color": "#4C6B7A", "text_color": "#EAF1F8", "label": "Longitudinal CA, MTF falloff, diffraction, and starburst for artistic lens looks."},
|
|
]
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
# lens_options = list(img_lens_effects.LENS_PROFILES.keys())
|
|
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
|
|
# "lens_profile": (lens_options, {"default": "None"}),
|
|
|
|
"use_vignette": ("BOOLEAN", {"default": False, "label_off": "Ignore vignette", "label_on": "Apply vignette"}),
|
|
"vignette_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"vignette_radius": ("FLOAT", {"default": 0.65, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"vignette_feather": ("FLOAT", {"default": 0.4, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"vignette_shape": (["circular", "oval", "corner"], {"default": "circular"}),
|
|
|
|
"use_chroma": ("BOOLEAN", {"default": False, "label_off": "Ignore chromatic aberration", "label_on": "Apply chromatic aberration"}),
|
|
"chroma_intensity": ("FLOAT", {"default": 0.1, "min": 0.0, "max": 10.0, "step": 0.1}),
|
|
"chroma_falloff": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"chroma_fringe_color": (["red_blue", "green_magenta", "yellow_purple"], {"default": "red_blue"}),
|
|
|
|
"use_bokeh": ("BOOLEAN", {"default": False, "label_off": "Ignore bokeh", "label_on": "Apply bokeh"}),
|
|
"bokeh_radius": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 40.0, "step": 0.5}),
|
|
"bokeh_blades": ("INT", {"default": 0, "min": 0, "max": 12, "step": 1}),
|
|
"bokeh_highlight_boost": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"bokeh_cat_eye": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_distortion": ("BOOLEAN", {"default": False, "label_off": "Ignore lens distortion", "label_on": "Apply lens distortion"}),
|
|
"distortion_barrel": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"distortion_pincushion": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"distortion_zoom": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 2.0, "step": 0.01}),
|
|
|
|
"use_flare": ("BOOLEAN", {"default": False, "label_off": "Ignore lens flare", "label_on": "Apply lens flare"}),
|
|
"flare_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"flare_pos_x": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"flare_pos_y": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"flare_streak_count": ("INT", {"default": 6, "min": 2, "max": 12, "step": 1}),
|
|
"flare_streak_length":("FLOAT", {"default": 0.4, "min": 0.1, "max": 1.0, "step": 0.01}),
|
|
"flare_ghost_count": ("INT", {"default": 4, "min": 0, "max": 8, "step": 1}),
|
|
"flare_color": (["warm", "cool", "neutral", "rainbow"], {"default": "warm"}),
|
|
|
|
"use_halation": ("BOOLEAN", {"default": False, "label_off": "Ignore halation", "label_on": "Apply halation"}),
|
|
"halation_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"halation_radius": ("FLOAT", {"default": 1.5, "min": 0.5, "max": 50.0, "step": 0.5}),
|
|
"halation_threshold": ("FLOAT", {"default": 0.75, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"halation_warmth": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_focus": ("BOOLEAN", {"default": False, "label_off": "Ignore focus falloff", "label_on": "Apply focus falloff"}),
|
|
"focus_blur_radius": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 30.0, "step": 0.5}),
|
|
"focus_mode": (["horizontal", "vertical", "radial", "oval"], {"default": "horizontal"}),
|
|
"focus_pos": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"focus_width": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"focus_feather": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_spherical": ("BOOLEAN", {"default": False, "label_off": "Ignore spherical aberration", "label_on": "Apply spherical aberration"}),
|
|
"spherical_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"spherical_radius": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 15.0, "step": 0.5}),
|
|
"spherical_zone": (["centre", "edge", "global"], {"default": "centre"}),
|
|
|
|
"use_anamorphic": ("BOOLEAN", {"default": False, "label_off": "Ignore anamorphic", "label_on": "Apply anamorphic"}),
|
|
"anamorphic_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"anamorphic_streak_color": (["blue", "warm", "white"], {"default": "blue"}),
|
|
"anamorphic_streak_length": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"anamorphic_oval_bokeh": ("FLOAT", {"default": 0.4, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"anamorphic_blue_bias": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
|
|
"use_coating_spectral": ("BOOLEAN", {"default": False, "label_off": "Ignore coating & spectral", "label_on": "Apply coating & spectral"}),
|
|
"coating_quality": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"spectral_red": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 1.5, "step": 0.01}),
|
|
"spectral_green": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 1.5, "step": 0.01}),
|
|
"spectral_blue": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 1.5, "step": 0.01}),
|
|
|
|
"use_advanced_aberrations": ("BOOLEAN", {"default": False, "label_off": "Ignore advanced aberrations", "label_on": "Apply advanced aberrations"}),
|
|
"field_curvature_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"astigmatism_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"astigmatism_angle": ("INT", {"default": 0, "min": -90, "max": 90, "step": 1}),
|
|
"coma_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"breathing_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"anamorphic_squeeze_ratio": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 2.0, "step": 0.01}),
|
|
|
|
"use_sensor_effects": ("BOOLEAN", {"default": False, "label_off": "Ignore sensor effects", "label_on": "Apply sensor effects"}),
|
|
"sensor_bloom_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"sensor_bloom_radius": ("FLOAT", {"default": 1.0, "min": 1.0, "max": 50.0, "step": 0.5}),
|
|
"sensor_bloom_threshold": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"glare_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"microlens_vignette_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"microlens_color_shift": ("FLOAT", {"default": 0.0, "min": -0.5, "max": 0.5, "step": 0.01}),
|
|
|
|
"use_creative_effects": ("BOOLEAN", {"default": False, "label_off": "Ignore creative effects", "label_on": "Apply creative effects"}),
|
|
"loca_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"mtf_falloff_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"diffraction_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"starburst_intensity": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_rasterix_lens(self, **kwargs):
|
|
p = SimpleNamespace(**kwargs)
|
|
pil_img = utility.tensor_to_image(p.image)
|
|
|
|
pil_img = img_lens_effects.img_lens_effect(
|
|
image=pil_img,
|
|
# Original effects (zero when disabled)
|
|
vignette_strength=p.vignette_strength if p.use_vignette else 0,
|
|
vignette_radius=p.vignette_radius,
|
|
vignette_feather=p.vignette_feather,
|
|
vignette_shape=p.vignette_shape,
|
|
|
|
chroma_intensity=p.chroma_intensity if p.use_chroma else 0,
|
|
chroma_falloff=p.chroma_falloff,
|
|
chroma_fringe_color=p.chroma_fringe_color,
|
|
|
|
bokeh_radius=p.bokeh_radius if p.use_bokeh else 0,
|
|
bokeh_blades=p.bokeh_blades,
|
|
bokeh_highlight_boost=p.bokeh_highlight_boost,
|
|
bokeh_cat_eye=p.bokeh_cat_eye,
|
|
|
|
distortion_barrel=p.distortion_barrel if p.use_distortion else 0,
|
|
distortion_pincushion=p.distortion_pincushion if p.use_distortion else 0,
|
|
distortion_zoom=p.distortion_zoom,
|
|
|
|
flare_intensity=p.flare_intensity if p.use_flare else 0,
|
|
flare_pos_x=p.flare_pos_x,
|
|
flare_pos_y=p.flare_pos_y,
|
|
flare_streak_count=p.flare_streak_count,
|
|
flare_streak_length=p.flare_streak_length,
|
|
flare_ghost_count=p.flare_ghost_count,
|
|
flare_color=p.flare_color,
|
|
|
|
halation_intensity=p.halation_intensity if p.use_halation else 0,
|
|
halation_radius=p.halation_radius,
|
|
halation_threshold=p.halation_threshold,
|
|
halation_warmth=p.halation_warmth,
|
|
|
|
focus_blur_radius=p.focus_blur_radius if p.use_focus else 0,
|
|
focus_mode=p.focus_mode,
|
|
focus_pos=p.focus_pos,
|
|
focus_width=p.focus_width,
|
|
focus_feather=p.focus_feather,
|
|
|
|
spherical_intensity=p.spherical_intensity if p.use_spherical else 0,
|
|
spherical_radius=p.spherical_radius,
|
|
spherical_zone=p.spherical_zone,
|
|
|
|
anamorphic_intensity=p.anamorphic_intensity if p.use_anamorphic else 0,
|
|
anamorphic_streak_color=p.anamorphic_streak_color,
|
|
anamorphic_streak_length=p.anamorphic_streak_length,
|
|
anamorphic_oval_bokeh=p.anamorphic_oval_bokeh,
|
|
anamorphic_blue_bias=p.anamorphic_blue_bias,
|
|
|
|
coating_quality=p.coating_quality if p.use_coating_spectral else 1.0,
|
|
spectral_red=p.spectral_red if p.use_coating_spectral else 1.0,
|
|
spectral_green=p.spectral_green if p.use_coating_spectral else 1.0,
|
|
spectral_blue=p.spectral_blue if p.use_coating_spectral else 1.0,
|
|
|
|
field_curvature_strength=p.field_curvature_strength if p.use_advanced_aberrations else 0,
|
|
astigmatism_strength=p.astigmatism_strength if p.use_advanced_aberrations else 0,
|
|
astigmatism_angle=p.astigmatism_angle if p.use_advanced_aberrations else 0,
|
|
coma_strength=p.coma_strength if p.use_advanced_aberrations else 0,
|
|
breathing_strength=p.breathing_strength if p.use_advanced_aberrations else 0,
|
|
anamorphic_squeeze_ratio=p.anamorphic_squeeze_ratio if p.use_advanced_aberrations else 1.0,
|
|
|
|
sensor_bloom_intensity=p.sensor_bloom_intensity if p.use_sensor_effects else 0,
|
|
sensor_bloom_radius=p.sensor_bloom_radius if p.use_sensor_effects else 10.0,
|
|
sensor_bloom_threshold=p.sensor_bloom_threshold if p.use_sensor_effects else 0.8,
|
|
glare_intensity=p.glare_intensity if p.use_sensor_effects else 0,
|
|
microlens_vignette_strength=p.microlens_vignette_strength if p.use_sensor_effects else 0,
|
|
microlens_color_shift=p.microlens_color_shift if p.use_sensor_effects else 0,
|
|
|
|
loca_intensity=p.loca_intensity if p.use_creative_effects else 0,
|
|
mtf_falloff_strength=p.mtf_falloff_strength if p.use_creative_effects else 0,
|
|
diffraction_strength=p.diffraction_strength if p.use_creative_effects else 0,
|
|
starburst_intensity=p.starburst_intensity if p.use_creative_effects else 0,
|
|
)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereHistogram:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_histogram"
|
|
CATEGORY = TREE_RASTERIX
|
|
OUTPUT_NODE = True
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
"show_histogram": ("BOOLEAN", {"default": False, "label_off": "Ignore histogram", "label_on": "Create histogram"}),
|
|
"histogram_channel": (["RGB", "RED", "GREEN", "BLUE"], {"default": "RGB"}),
|
|
"histogram_style": (["bars", "lines", "waveform", "heatmap", "stacked", "luma", "parade", "gradient", "glow", "dots", "step", "log", "percentile", "inverse"], {"default": "bars"}),
|
|
},
|
|
"hidden": {
|
|
"id": "UNIQUE_ID",
|
|
}
|
|
}
|
|
|
|
def primere_histogram(self, image, precision, show_histogram=False, histogram_channel="RGB", histogram_style="bars", id=None):
|
|
pil_img = utility.tensor_to_image(image)
|
|
pil_img_input = pil_img.copy()
|
|
|
|
histogram.rasterix_hist_cache_store(pil_img_input, pil_img, precision, node_id=id)
|
|
|
|
if show_histogram:
|
|
histogram.rasterix_hist_cache_store(pil_img_input, pil_img, precision, node_id=id)
|
|
active_hist = histogram.rasterix_hist_render_selected(pil_img_input, pil_img, precision, True, histogram_channel, histogram_style, node_id=id)
|
|
suffix = ''.join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for _ in range(8))
|
|
temp_file = f"rasterix_hist_{suffix}.png"
|
|
active_hist.save(os.path.join(folder_paths.temp_directory, temp_file), compress_level=1)
|
|
return {"ui": {"images": [{"filename": temp_file, "subfolder": "", "type": "temp"}]}, "result": (utility.image_to_tensor(pil_img),), }
|
|
else:
|
|
INVALID_IMAGE_PATH = os.path.join(PRIMERE_ROOT, 'front_end', 'images')
|
|
INVALID_IMAGE = os.path.join(INVALID_IMAGE_PATH, "No_histogram_08.jpg")
|
|
images = utility.ImageLoaderFromPath(INVALID_IMAGE)
|
|
r1 = random.randint(1000, 9999)
|
|
temp_filename = f"Primere_ComfyUI_{r1}.png"
|
|
os.makedirs(folder_paths.get_temp_directory(), exist_ok=True)
|
|
TEMP_FILE = os.path.join(folder_paths.get_temp_directory(), temp_filename)
|
|
utility.tensor_to_image(images[0]).save(TEMP_FILE)
|
|
return {"ui": {"images": [{"filename": temp_filename, "subfolder": "", "type": "temp"}]}, "result": (utility.image_to_tensor(pil_img),),}
|
|
|
|
class PrimereSolarizationBW:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_solarization_bw"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_solarization": ("BOOLEAN", {"default": False, "label_off": "Ignore solarization", "label_on": "Apply solarization"}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
|
|
"color_mode": ("BOOLEAN", {"default": False, "label_off": "Keep unchanged", "label_on": "Force B&W"}),
|
|
"strength": ("FLOAT", {"default": 0.6, "min": 0.0, "max": 2.0, "step": 0.01}),
|
|
"pivot": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"sigma": ("FLOAT", {"default": 0.18, "min": 0.01, "max": 0.5, "step": 0.01}),
|
|
"edge_boost": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 3.0, "step": 0.05}),
|
|
"edge_radius": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 3.0, "step": 0.1}),
|
|
"contrast": ("FLOAT", {"default": 1.1, "min": 0.5, "max": 2.0, "step": 0.01}),
|
|
"hard_paper": ("BOOLEAN", {"default": False, "label_off": "Soft paper", "label_on": "Hard paper"}),
|
|
"grain_modulation": ("BOOLEAN", {"default": False, "label_off": "No grain modulation", "label_on": "Grain-modulated inversion"}),
|
|
"grain_strength": ("FLOAT", {"default": 0.15, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"grain_scale": ("FLOAT", {"default": 1.0, "min": 0.3, "max": 3.0, "step": 0.1}),
|
|
|
|
},
|
|
"optional": {
|
|
"seed": ("INT", {"default": 0, "min": 0, "max": utility.MAX_SEED, "forceInput": True}),
|
|
}
|
|
}
|
|
|
|
def primere_solarization_bw(self, image, color_mode, use_solarization, precision, strength, pivot, sigma, edge_boost, edge_radius, contrast, hard_paper, grain_modulation, grain_strength, grain_scale, seed = None):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_solarization:
|
|
pil_img = img_solarization_bw.img_solarization_bw(image=pil_img, color_mode=color_mode, strength=strength, pivot=pivot, sigma=sigma, edge_boost=edge_boost, edge_radius=edge_radius, contrast=contrast, precision=precision, hard_paper=hard_paper, grain_modulation=grain_modulation, grain_strength=grain_strength, grain_scale=grain_scale, seed=seed)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereClarity:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_clarity"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_clarity": ("BOOLEAN", {"default": False, "label_off": "Ignore clarity", "label_on": "Apply clarity"}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
|
|
"strength": ("FLOAT", {"default": 0.5, "min": -2.0, "max": 3.0, "step": 0.01}),
|
|
"radius": ("FLOAT", {"default": 2.0, "min": 0.5, "max": 10.0, "step": 0.1}),
|
|
"midtone_range": ("FLOAT", {"default": 0.5, "min": 0.1, "max": 1.0, "step": 0.01}),
|
|
"edge_preservation": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_clarity(self, image, use_clarity, precision, strength, radius, midtone_range, edge_preservation):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_clarity and strength != 0:
|
|
pil_img = img_clarity.img_clarity(image=pil_img, strength=strength, radius=radius, midtone_range=midtone_range, edge_preservation=edge_preservation, precision=precision)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereDehaze:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_dehaze"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_dehaze": ("BOOLEAN", {"default": False, "label_off": "Ignore dehaze", "label_on": "Apply dehaze"}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
|
|
"strength": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 2.0, "step": 0.01}),
|
|
"radius": ("INT", {"default": 15, "min": 3, "max": 100, "step": 1}),
|
|
"omega": ("FLOAT", {"default": 0.95, "min": 0.5, "max": 1.0, "step": 0.01}),
|
|
"t0": ("FLOAT", {"default": 0.1, "min": 0.01, "max": 0.5, "step": 0.01}),
|
|
"contrast": ("FLOAT", {"default": 1.05, "min": 0.5, "max": 2.0, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_dehaze(self, image, use_dehaze, precision, strength, radius, omega, t0, contrast):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_dehaze and strength > 0:
|
|
pil_img = img_dehaze.img_dehaze(image=pil_img, strength=strength, radius=radius, omega=omega, t0=t0, contrast=contrast, precision=precision)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereLocalLaplacian:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_local_laplacian"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_local_laplacian": ("BOOLEAN", {"default": False, "label_off": "Ignore local laplacian", "label_on": "Apply local laplacian"}),
|
|
|
|
"sigma": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 5.0, "step": 0.1}),
|
|
"contrast": ("FLOAT", {"default": 1.2, "min": 0.5, "max": 3.0, "step": 0.01}),
|
|
"detail": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
|
|
"levels": ("INT", {"default": 8, "min": 4, "max": 32, "step": 1}),
|
|
}
|
|
}
|
|
|
|
def primere_local_laplacian(self, image, use_local_laplacian, sigma, contrast, detail, levels):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_local_laplacian:
|
|
pil_img = img_local_laplacian.img_local_laplacian(image=pil_img, sigma=sigma, contrast=contrast, detail=detail, levels=levels)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereFrequencySeparation:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_frequency_separation"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_frequency_separation": ("BOOLEAN", {"default": False, "label_off": "Ignore frequency separation", "label_on": "Apply frequency separation"}),
|
|
|
|
"radius": ("FLOAT", {"default": 3.0, "min": 0.5, "max": 20.0, "step": 0.1}),
|
|
"low_freq_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
|
|
"high_freq_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 3.0, "step": 0.01}),
|
|
"blend_mode": (["add", "multiply", "overlay"], {"default": "add"}),
|
|
}
|
|
}
|
|
|
|
def primere_frequency_separation(self, image, use_frequency_separation, radius, low_freq_strength, high_freq_strength, blend_mode):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_frequency_separation:
|
|
pil_img = img_frequency_separation.img_frequency_separation(image=pil_img, radius=radius, low_freq_strength=low_freq_strength, high_freq_strength=high_freq_strength, blend_mode=blend_mode)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereFilmicCurve:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_filmic_curve"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_filmic": ("BOOLEAN", {"default": False, "label_off": "Ignore filmic", "label_on": "Apply filmic"}),
|
|
|
|
"curve_type": (["filmic", "log"], {"default": "filmic"}),
|
|
"contrast": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 2.0, "step": 0.01}),
|
|
"highlight_rolloff": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"shadow_lift": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 0.5, "step": 0.01}),
|
|
"pivot": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_filmic_curve(self, image, use_filmic, curve_type, contrast, highlight_rolloff, shadow_lift, pivot):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_filmic:
|
|
pil_img = img_filmic_curve.img_filmic_curve(image=pil_img, curve_type=curve_type, contrast=contrast, highlight_rolloff=highlight_rolloff, shadow_lift=shadow_lift, pivot=pivot)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereLUT3D:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_lut3d"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
LUT_DIR = os.path.join(PRIMERE_ROOT, 'components', 'images', 'luts')
|
|
|
|
@classmethod
|
|
def _list_luts(cls):
|
|
lut_entries = ["None"]
|
|
if not os.path.exists(cls.LUT_DIR):
|
|
return lut_entries
|
|
|
|
for f in sorted(os.listdir(cls.LUT_DIR)):
|
|
full_path = os.path.join(cls.LUT_DIR, f)
|
|
if os.path.isfile(full_path) and f.lower().endswith(".cube"):
|
|
lut_entries.append(f)
|
|
|
|
for d in sorted(os.listdir(cls.LUT_DIR)):
|
|
subdir = os.path.join(cls.LUT_DIR, d)
|
|
if os.path.isdir(subdir):
|
|
for f in sorted(os.listdir(subdir)):
|
|
if f.lower().endswith(".cube"):
|
|
lut_entries.append(f"{d}/{f}")
|
|
|
|
return lut_entries
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_lut": ("BOOLEAN", {"default": False, "label_off": "Ignore LUT", "label_on": "Apply LUT"}),
|
|
|
|
"lut_file": (cls._list_luts(),),
|
|
"intensity": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.01}),
|
|
"color_space": (["sRGB", "linear"], {"default": "sRGB"}),
|
|
}
|
|
}
|
|
|
|
def primere_lut3d(self, image, use_lut, lut_file, intensity, color_space):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_lut and lut_file != "None":
|
|
lut_path = os.path.join(self.LUT_DIR, lut_file)
|
|
pil_img = img_lut3d.img_lut3d(image=pil_img, lut_path=lut_path, intensity=intensity, input_space=color_space, output_space=color_space)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereEdgeJitter:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_edge_jitter"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_edge_jitter": ("BOOLEAN", {"default": False, "label_off": "Ignore edge jitter", "label_on": "Apply edge jitter"}),
|
|
"precision": ("BOOLEAN", {"default": False, "label_off": "8 bit", "label_on": "16 bit"}),
|
|
|
|
"strength": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 3.0, "step": 0.01}),
|
|
"radius": ("FLOAT", {"default": 1.5, "min": 0.5, "max": 5.0, "step": 0.1}),
|
|
"edge_threshold": ("FLOAT", {"default": 0.1, "min": 0.01, "max": 0.5, "step": 0.01}),
|
|
"randomness": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
},
|
|
"optional": {
|
|
"seed": ("INT", {"default": 0, "min": 0, "max": utility.MAX_SEED, "forceInput": True}),
|
|
}
|
|
}
|
|
|
|
def primere_edge_jitter(self, image, use_edge_jitter, precision, strength, radius, edge_threshold, randomness, seed=None):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_edge_jitter and strength > 0:
|
|
pil_img = img_edge_jitter.img_edge_jitter(image=pil_img, strength=strength, radius=radius, edge_threshold=edge_threshold, randomness=randomness, seed=seed, precision=precision)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimereDepthBlur:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_depth_blur"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_depth_blur": ("BOOLEAN", {"default": False, "label_off": "Ignore depth blur", "label_on": "Apply depth blur"}),
|
|
"auto_optimize": ("BOOLEAN", {"default": False, "label_off": "Use custom inputs", "label_on": "Optimize settings by focus"}),
|
|
"use_DA_v3": ("BOOLEAN", {"default": False, "label_off": "Depth-anything V2", "label_on": "Depth-anything V3"}),
|
|
"DA_model": (["small", "base", "large", "mono", "metric", "giant", "nested"], {"default": "large"}),
|
|
"focus_depth": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"depth_range": ("FLOAT", {"default": 0.200, "min": 0.001, "max": 1.000, "step": 0.001}),
|
|
"max_blur": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 50.0, "step": 0.5}),
|
|
"depth_gamma": ("FLOAT", {"default": 1.00, "min": 0.10, "max": 5.00, "step": 0.01}),
|
|
}
|
|
}
|
|
|
|
def primere_depth_blur(self, image, use_depth_blur, auto_optimize, use_DA_v3, DA_model, focus_depth, depth_range, max_blur, depth_gamma):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_depth_blur and focus_depth > 0 and max_blur > 0:
|
|
pil_img = img_depth_blur.img_depth_blur(image=pil_img, focus_depth=focus_depth, depth_range=depth_range, max_blur=max_blur, depth_gamma=depth_gamma, auto_optimize=auto_optimize, use_v3=use_DA_v3, DA_model=DA_model)
|
|
|
|
return (utility.image_to_tensor(pil_img),)
|
|
|
|
class PrimerePhotoPaper:
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("IMAGE",)
|
|
FUNCTION = "primere_photo_paper"
|
|
CATEGORY = TREE_RASTERIX
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {"forceInput": True}),
|
|
"use_photo_paper": ("BOOLEAN", {"default": False, "label_off": "Ignore photo paper", "label_on": "Apply photo paper"}),
|
|
"photo_paper": (list(PAPER_PRESETS.keys()), {"default": list(PAPER_PRESETS.keys())[0]}),
|
|
"color_paper": ("BOOLEAN", {"default": False, "label_off": "B&W paper", "label_on": "Color paper"}),
|
|
"paper_base": (["RC", "FB"], {"default": "RC"}),
|
|
"paper_expiration_years": ("FLOAT", {"default": 0, "min": 0, "max": 30, "step": 0.1}),
|
|
"paper_intensity": ("FLOAT", {"default": 100, "min": 0, "max": 200, "step": 1}),
|
|
}
|
|
}
|
|
|
|
def primere_photo_paper(self, image, use_photo_paper, photo_paper, color_paper, paper_base, paper_intensity, paper_expiration_years):
|
|
pil_img = utility.tensor_to_image(image)
|
|
if use_photo_paper and paper_intensity != 0:
|
|
pil_img = img_photo_paper.img_photo_paper(image=pil_img, paper_type=photo_paper, color_paper=color_paper, paper_base=paper_base, paper_intensity=paper_intensity, expiration_years=paper_expiration_years)
|
|
|
|
return (utility.image_to_tensor(pil_img),) |