"""Luminance-controlled palettes shared by SDR and HDR output.""" import math SRGB_Y = (0.2126, 0.7152, 0.0722) BT2020_Y = (0.2627, 0.6780, 0.0593) TO_2020 = ((0.6274039, 0.3292830, 0.0433131), (0.0690973, 0.9195404, 0.0113623), (0.0163914, 0.0880133, 0.8955953)) ORIGINAL_BLUE = '#3b73fa' GRADIENT_STEPS = 32 def linear_srgb(color): values = (int(color[i:i + 2], 16) / 255 for i in (1, 3, 5)) return tuple(v / 12.92 if v <= 0.04045 else ((v + .055) / 1.055) ** 2.4 for v in values) def gradient_level(position): """32 perceptually separated levels, with exact dark and bright endpoints.""" t = round(min(1, max(0, position)) * (GRADIENT_STEPS - 1)) / (GRADIENT_STEPS - 1) return .005 + .995 * t ** 2.2 SDR_PEAK_Y = sum(v * w for v, w in zip(linear_srgb(ORIGINAL_BLUE), SRGB_Y)) def equal_luminance(color, target, channel_limit, *, hdr=False): """Scale linear RGB equally, preserving chromaticity without adding white.""" rgb = linear_srgb(color) weights = BT2020_Y if hdr else SRGB_Y if hdr: rgb = tuple(sum(a * b for a, b in zip(row, rgb)) for row in TO_2020) luminance = sum(a * b for a, b in zip(rgb, weights)) if luminance <= 0: return (target,) * 3 rgb = tuple(v * target / luminance for v in rgb) maximum = max(rgb) if maximum > channel_limit + 1e-6: raise ValueError('Requested luminance exceeds the color-preserving channel limit') return rgb def sdr_color(base, level=1.0): # Scale a fixed peak color to keep chromaticity constant along the trail. peak = equal_luminance(base, SDR_PEAK_Y, 1.0) rgb = [max(0, min(1, v * level)) for v in peak] rgb = [12.92 * v if v <= .0031308 else 1.055 * v ** (1 / 2.4) - .055 for v in rgb] return '#' + ''.join(f'{round(v * 255):02x}' for v in rgb) def validate_peak(peak): if not math.isfinite(peak) or not 100 <= peak <= 2000: raise ValueError('--peak-nits must be between 100 and 2000')