Skip to content

pixtreme.color

color

Color and lookup-table transforms.

__all__ = ('apply_lut', 'gamma_to_linear', 'hsv_to_rgb', 'linear_to_gamma', 'rgb_to_grayscale', 'rgb_to_hsv', 'rgb_to_rgb', 'rgb_to_ycbcr', 'ycbcr_to_rgb', 'ycbcr_to_ycbcr', 'equalize_histogram', 'clahe', 'chromatic_adaptation', 'white_balance', 'white_point_simulation') module-attribute

clahe(frame, *, clip_limit=2.0, tiles_y=8, tiles_x=8, domain=(0.0, 1.0), bins=1024)

Apply deterministic contrast-limited adaptive histogram equalization.

The signature is clahe(frame, *, clip_limit=2.0, tiles_y=8, tiles_x=8, domain=(0.0, 1.0), bins=1024) -> Frame. tiles_y and tiles_x declare the vertical and horizontal split counts. The domain tuple declares the histogram interval. Values are clamped to it and use min(floor(normalized * bins), bins - 1). Work is per channel without channel-label semantics. Fixed ceil-sized tiles receive bottom/right mirror padding with edge-excluding reflection. A tile bin is capped at cap = clip_limit * tile pixels / bins; excess is restored by the unique uniform water-fill that preserves every count without exceeding the cap. Direct tile CDFs are looked up at tile-center positions, and bilinear interpolation clamps at the outer tile centers without wrap. Output values lie in [0, 1] without a final clip or renormalization.

A choice where bins exceeds the padded tile pixel count is valid, but its sparse statistics and possible banding should be checked on the actual material. The result is a private C-contiguous float32 Frame with shape and metadata preserved; the input remains unchanged. Convert non-float32 storage by its value meaning with px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize first.

equalize_histogram(frame, *, domain=(0.0, 1.0), bins=1024)

Equalize each channel of a float32 Frame with its direct empirical CDF.

The signature is equalize_histogram(frame, *, domain=(0.0, 1.0), bins=1024) -> Frame. domain=(minimum, maximum) declares the histogram interval. Values are clamped to that interval and their bin is min(floor(normalized * bins), bins - 1). Processing is per channel: each channel builds its own direct empirical CDF from every pixel, with no CDF-min subtraction, input min-max inference, or channel combination. Output values lie in [0, 1], and a uniform channel maps to 1.0 rather than receiving a special case.

The result is a private C-contiguous float32 Frame with shape and metadata preserved; the input remains unchanged. Convert non-float32 storage by its value meaning with px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize before calling this operation.

hsv_to_rgb(frame)

Convert an exact label-driven H/S/V float32 Frame to canonical R/G/B.

hsv_to_rgb(frame) -> Frame accepts no domain, range, clip, or metadata override. The input must contain exactly one each of the H, S, and V labels in any order. H is wrapped modulo 1 before selecting one of six sectors; C = V * S, X = C * (1 - abs((6 * H modulo 2) - 1)), and m = V - C form the sector result. S and V enter these equations unchanged, V retains unbounded scene scale, and S zero returns (V, V, V). Nonnegative finite RGB produced by :func:rgb_to_hsv round-trips; negative and nonfinite values are accepted but carry no round-trip guarantee.

The result is a new C-contiguous float32 Frame with R/G/B labels in that order. It preserves colorspace and gamma, sets matrix to None, and leaves the input Frame and storage unchanged. Convert other dtypes according to value meaning with px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize before calling this function.

rgb_to_hsv(frame)

Convert an exact label-driven R/G/B float32 Frame to canonical H/S/V.

rgb_to_hsv(frame) -> Frame accepts no domain, range, clip, or metadata override. The input must contain exactly one each of the R, G, and B labels in any order. With delta = maximum - minimum, V is maximum, S is delta / maximum except that maximum zero produces S zero, and H uses the maximum R/G/B sector equation divided by six and reduced modulo 1. V retains unbounded scene scale. Nonnegative finite RGB round-trips through :func:hsv_to_rgb; negative and nonfinite values are accepted but carry no nominal-range or round-trip guarantee.

The result is a new C-contiguous float32 Frame with H/S/V labels in that order. It preserves colorspace and gamma, sets matrix to None, and leaves the input Frame and storage unchanged. Convert other dtypes according to value meaning with px.values.cast_dtype, px.values.recode_dtype, or px.values.dequantize before calling this function.

apply_lut(frame, *, lut, interpolation=None)

Apply a user-provided 1D or 3D LUT to a float32 Frame's RGB labels.

User LUT values do not declare color meaning, so Frame colorspace and gamma metadata pass through unchanged. Other channel labels pass through by value. Lookup coordinates use the LUT's per-channel domain with input clamp at its endpoints; output values are not clipped. None selects tetrahedral for a 3D Lut and linear for a Lut1D. No shaper stage is implied. Neither input is mutated, and the result owns new C-contiguous Frame storage.

gamma_to_linear(frame, *, gamma=None)

Decode a claimed RGB transfer to scene-linear values on the GPU.

frame must be a float32 Frame containing exactly one R, G, and B. gamma is an input metadata claim; None uses frame.gamma. Explicit canonical values are linear, sRGB, Rec.709, BT.1886, PQ, HLG, ACEScc, ACEScct, S-Log, S-Log2, S-Log3, ARRI-LogC3, ARRI-LogC4, Blackmagic-Film-Gen-5, DaVinci-Intermediate, RED-Log3G10, REDlogFilm, Canon-Log, Canon-Log-2, Canon-Log-3, V-Log, D-Log, F-Log, F-Log2, N-Log, L-Log, Apple-Log, Samsung-Log, Cineon, Gamma-2.2, Gamma-2.4, Gamma-2.5, or Gamma-2.6 tokens. The claim controls interpretation without mutating the input Frame metadata.

Only R/G/B values are decoded. Auxiliary channels and channel order are preserved bit for bit, colorspace is inherited, output gamma is "linear", and matrix metadata is cleared. Negative and above-one scene values follow each transfer's documented extension and are not clipped. A new Frame and GPU allocation are returned even for a linear claim. Invalid frame types, dtypes, RGB labels, or gamma tokens raise :class:ValueError.

S-Log / S-Log2 / S-Log3 apply their lower linear branches directly to signed inputs. For S-Log and S-Log2, public scene-linear reflectance uses x = r / 0.9 and Sony encoded IRE uses the public embedding e = (64 + 876 * y) / 1023. S-Log3 / ARRI-LogC4 do not use sign/magnitude mirroring; ARRI-LogC4 retains its negative scene cut. Established S-Log3 and ARRI-LogC4 results for nonnegative inputs remain float32 bit-identical. ARRI-LogC3 is the ARRI EI 800 relative scene-exposure curve, maps 18% gray to 400 / 1023, and extends its lower linear branch to negative values without clipping or sign/magnitude mirroring. Blackmagic Film Gen 5 uses its published natural-log branches. DaVinci Intermediate uses its published base-2 branches and a derived decode threshold. Both apply their lower linear branches directly to negative values. RED-Log3G10 uses RED's published base-10 curve with a directly extended lower branch below scene-linear -0.01. REDlogFilm uses the Cineon sign-preserving mirror and exact float32 bits while preserving its own metadata. Canon-Log, Canon-Log-2, and Canon-Log-3 map reflectance with x = r / 0.9 and apply Canon's 2018 signed branches directly without clipping or sign/magnitude mirroring. Canon-Log-3 derives both decode cuts from its linear branch. V-Log applies Panasonic's logarithmic branch directly to reflectance and uses its tangent-derived lower branch and decode threshold, extending signed and overshoot values without clipping or sign/magnitude mirroring. D-Log, F-Log, and F-Log2 apply their published linear and logarithmic branches directly to reflectance. Each uses the branches' maximum-real-root intersection as its encode cut and the independently rounded encoded intersection as its decode cut; equality is logarithmic, and signed and overshoot values remain unclipped. N-Log uses its maximum-real-root intersection and signed cube-root extension; L-Log uses a tangent-derived lower branch. Apple-Log preserves its published collapse below R0 and encoded zero, while Samsung-Log extends its continuity-derived lower logarithmic branch without codec clipping. All four take reflectance directly, remain independent from colorspace, and leave scene overshoot unclipped. Gamma-2.5 is sign-preserving pure power. ACEScc uses the Academy lower inverse through encoded (9.72 - 15) / 17.52 and its logarithmic inverse above it; ACEScct uses the published linear inverse through 0.155251141552511 and its logarithmic inverse above it. Both use scene-linear components directly, infer no colorspace, and extend analytically above linear 65504 without clipping.

linear_to_gamma(frame, *, gamma)

Encode scene-linear RGB with an explicit transfer on the GPU.

frame must be a float32 Frame with frame.gamma == "linear" and exactly one R, G, and B. gamma is a required normalized output token: linear, sRGB, Rec.709, BT.1886, PQ, HLG, ACEScc, ACEScct, S-Log, S-Log2, S-Log3, ARRI-LogC3, ARRI-LogC4, Blackmagic-Film-Gen-5, DaVinci-Intermediate, RED-Log3G10, REDlogFilm, Canon-Log, Canon-Log-2, Canon-Log-3, V-Log, D-Log, F-Log, F-Log2, N-Log, L-Log, Apple-Log, Samsung-Log, Cineon, Gamma-2.2, Gamma-2.4, Gamma-2.5, or Gamma-2.6. Passing None or an unknown token is rejected rather than inferred.

Only R/G/B values are encoded. Auxiliary channels and channel order are preserved bit for bit, colorspace is inherited, output gamma is the requested token, and matrix metadata is cleared. Negative and above-one scene values follow each transfer's documented extension and are not clipped; a new Frame and GPU allocation are always returned. Invalid frame types, dtypes, RGB labels, gamma tokens, or non-linear input metadata raise :class:ValueError.

S-Log / S-Log2 / S-Log3 apply their lower linear branches directly to signed inputs. For S-Log and S-Log2, public scene-linear reflectance uses x = r / 0.9 and Sony encoded IRE uses the public embedding e = (64 + 876 * y) / 1023. S-Log3 / ARRI-LogC4 do not use sign/magnitude mirroring; ARRI-LogC4 retains its negative scene cut. Established S-Log3 and ARRI-LogC4 results for nonnegative inputs remain float32 bit-identical. ARRI-LogC3 is the ARRI EI 800 relative scene-exposure curve, maps 18% gray to 400 / 1023, and extends its lower linear branch to negative values without clipping or sign/magnitude mirroring. Blackmagic Film Gen 5 uses its published natural-log branches. DaVinci Intermediate uses its published base-2 branches and a derived decode threshold. Both apply their lower linear branches directly to negative values. RED-Log3G10 uses RED's published base-10 curve with a directly extended lower branch below scene-linear -0.01. REDlogFilm uses the Cineon sign-preserving mirror and exact float32 bits while preserving its own metadata. Canon-Log, Canon-Log-2, and Canon-Log-3 map reflectance with x = r / 0.9 and apply Canon's 2018 signed branches directly without clipping or sign/magnitude mirroring. Canon-Log-3 includes both x = +/-0.014 cuts in its linear branch and derives both decode thresholds from that branch. V-Log applies Panasonic's logarithmic branch directly to reflectance and uses its tangent-derived lower branch and decode threshold, extending signed and overshoot values without clipping or sign/magnitude mirroring. D-Log, F-Log, and F-Log2 apply their published linear and logarithmic branches directly to reflectance. Each uses the branches' maximum-real-root intersection as its encode cut and the independently rounded encoded intersection as its decode cut; equality is logarithmic, and signed and overshoot values remain unclipped. N-Log uses its maximum-real-root intersection and signed cube-root extension; L-Log uses a tangent-derived lower branch. Apple-Log preserves its published collapse below R0 and encoded zero, while Samsung-Log extends its continuity-derived lower logarithmic branch without codec clipping. All four take reflectance directly, remain independent from colorspace, and leave scene overshoot unclipped. Gamma-2.5 uses sign(x) * abs(x) ** 0.4. ACEScc uses the Academy constant branch for x <= 0, lower logarithmic branch for 0 < x < 2-15, and upper logarithmic branch from 2-15. ACEScct uses its published linear toe through x = 0.0078125 and logarithmic branch above it. Both use scene-linear components directly, infer no colorspace, and add no upper clip, LUT, or gamut transform.

rgb_to_grayscale(frame, *, colorspace=None, gamma=None, matrix=None)

Project RGB to the Y channel of a declared full-range representation.

frame must be a float32 Frame containing exactly one R, G, and B and no YCbCr destination labels. colorspace and gamma declare the projection representation; None inherits Frame metadata. They use the closed Frame colorspace vocabulary and the linear, sRGB, Rec.709, BT.1886, PQ, HLG, ACEScc, ACEScct, S-Log, S-Log2, S-Log3, ARRI-LogC3, ARRI-LogC4, Blackmagic-Film-Gen-5, DaVinci-Intermediate, RED-Log3G10, REDlogFilm, Canon-Log, Canon-Log-2, Canon-Log-3, V-Log, D-Log, F-Log, F-Log2, N-Log, L-Log, Apple-Log, Samsung-Log, Cineon, Gamma-2.2, Gamma-2.4, Gamma-2.5, and Gamma-2.6 gamma tokens. The colorspace vocabulary includes P3-DCI, P3-D60, P3-D65, SMPTE-C, Canon-Cinema-Gamut, V-Gamut, D-Gamut, F-Gamut-C, and Apple-Wide-Gamut independently from gamma selection. matrix accepts "BT.601", "BT.709", "BT.2020", or "native" and otherwise resolves from the declared representation.

The GPU result is a new C-contiguous float32 Frame with only the ("Y",) channel; auxiliary channels are intentionally omitted. It stamps the declared colorspace and gamma plus the resolved matrix. Linear output represents luminance and non-linear output represents luma. The projection matches the Y channel of :func:rgb_to_ycbcr with full range and does not clip scene values. Invalid frame types, dtypes, labels, or tokens raise :class:ValueError.

rgb_to_ycbcr(frame, *, colorspace=None, gamma=None, matrix=None, range='full', bit_depth=8)

Encode RGB as full- or legal-range YCbCr in one fused GPU pass.

frame must be a float32 Frame containing exactly one R, G, and B and no YCbCr destination labels. colorspace and gamma declare the output representation; None inherits the corresponding Frame metadata. They use the same case- and separator-insensitive closed vocabularies as Frame, including sRGB / Rec.709 / Rec.2020 / ACES and S-Gamut colorspaces and linear / sRGB / Rec.709 / BT.1886 / PQ / HLG / ACEScc / ACEScct / S-Log / S-Log2 / S-Log3 / ARRI-LogC3 / ARRI-LogC4 / Blackmagic-Film-Gen-5 / DaVinci-Intermediate / RED-Log3G10 / REDlogFilm / Canon-Log / Canon-Log-2 / Canon-Log-3 / V-Log / D-Log / F-Log / F-Log2 / N-Log / L-Log / Apple-Log / Samsung-Log / Cineon / Gamma-2.2 / Gamma-2.4 / Gamma-2.5 / Gamma-2.6 transfers. The colorspace vocabulary includes P3-DCI, P3-D60, P3-D65, SMPTE-C, Canon-Cinema-Gamut, V-Gamut, D-Gamut, and F-Gamut-C and Apple-Wide-Gamut independently from gamma selection.

matrix accepts "BT.601", "BT.709", "BT.2020", or "native". When omitted, the target representation resolves it to BT.709, BT.2020, native, or the documented non-linear fallback. range is "full" or "legal"; bit_depth is 8, 10, 12, 14, or 16 and affects only legal-range scaling.

The result replaces R/G/B labels in place with Y/Cb/Cr, stamps the declared representation and resolved matrix, and preserves auxiliary channels bit for bit. Technical conversion, matrix encoding, and range mapping are fused; no scene values are clipped. Invalid frame types, dtypes, labels, tokens, ranges, or bit depths raise :class:ValueError.

ycbcr_to_rgb(frame, *, colorspace=None, gamma=None, matrix=None, range='full', bit_depth=8)

Decode full- or legal-range YCbCr to a declared RGB representation.

frame must be a float32 Frame containing exactly one Y, Cb, and Cr and no RGB destination labels. range accepts "full" or "legal" and bit_depth accepts 8, 10, 12, 14, or 16; legal code values are expanded before matrix decoding. matrix accepts "BT.601", "BT.709", "BT.2020", or "native" and resolves in order from the explicit value, frame.matrix, or the sRGB/Rec.709/Rec.2020 convention. Other colorspaces require an explicit matrix when provenance is absent.

colorspace and gamma declare the output RGB representation, with None inheriting Frame metadata. They accept the Frame colorspace vocabulary and the linear, sRGB, Rec.709, BT.1886, PQ, HLG, ACEScc, ACEScct, S-Log, S-Log2, S-Log3, ARRI-LogC3, ARRI-LogC4, Blackmagic-Film-Gen-5, DaVinci-Intermediate, RED-Log3G10, REDlogFilm, Canon-Log, Canon-Log-2, Canon-Log-3, V-Log, D-Log, F-Log, F-Log2, N-Log, L-Log, Apple-Log, Samsung-Log, Cineon, Gamma-2.2, Gamma-2.4, Gamma-2.5, and Gamma-2.6 transfer tokens. The colorspace vocabulary includes P3-DCI, P3-D60, P3-D65, SMPTE-C, Canon-Cinema-Gamut, V-Gamut, D-Gamut, F-Gamut-C, and Apple-Wide-Gamut independently from gamma selection.

The result replaces Y/Cb/Cr labels in place with R/G/B, preserves auxiliary channels bit for bit, stamps the declared colorspace and gamma, and clears matrix metadata. Range expansion, matrix decoding, and technical conversion are fused on the GPU without clipping. Invalid frame types, dtypes, labels, tokens, ranges, bit depths, or unresolvable matrix provenance raise :class:ValueError.

ycbcr_to_ycbcr(frame, *, colorspace=None, gamma=None, input_matrix=None, output_matrix=None, input_range='full', input_bit_depth=8, output_range='full', output_bit_depth=8)

Re-express YCbCr in one fused pass without exposing an RGB Frame.

For example, input_matrix="BT.709", output_matrix="native" converts a Rec.709 container convention to the working colorspace's own-row basis. Reversing those arguments performs the inverse rematrix.

Parameters

frame: A float32 Frame containing exactly one Y, Cb, and Cr and no RGB destination labels. Its colorspace and gamma declare the input representation. colorspace, gamma: Output representation tokens. None independently inherits the corresponding input Frame metadata. input_matrix: Input YCbCr basis: "BT.601", "BT.709", "BT.2020", or "native". Omission resolves in order from frame.matrix, the sRGB/Rec.709/Rec.2020 convention, or an error when provenance is absent. input_range, input_bit_depth: Independent input code grid. Range is "full" or "legal" and bit depth is 8, 10, 12, 14, or 16. output_matrix: Output YCbCr basis from the same four-token set. When omitted, the same colorspace retains the resolved input basis; a changed colorspace uses the encode resolver (BT.709, BT.2020, native for other linear output, or BT.709 for other encoded output). output_range, output_bit_depth: Independent output code grid with the same range and bit-depth domains.

Returns

Frame A new float32 Frame with Y/Cb/Cr labels and auxiliary channel order preserved, output metadata stamped, and the resolved output matrix. Input range expansion, matrix decoding, technical conversion, output matrix encoding, and range mapping run in one fused GPU pass without clipping scene values.

Raises

ValueError If the Frame type, dtype, labels, representation tokens, matrix provenance, ranges, or bit depths are invalid.

rgb_to_rgb(frame, *, input_colorspace=None, input_gamma=None, output_colorspace=None, output_gamma=None, tonemap=None)

Transform a float32 Frame's RGB colorimetry. With tonemap=None this is a technical conversion without rendering; ACES tonemaps perform rendering, while tonemap="BT.2408" performs direct mapping.

A simultaneous colorspace and transfer conversion runs decode, the Bradford- adapted primaries matrix, and encode in a single fused pass. Express the full conversion in one call: separate partial calls require additional passes. Channels are label-driven; R, G, and B are transformed while all other labels pass through unchanged. tonemap="ACES-1.3" and tonemap="ACES-2.0" evaluate the corresponding analytic ACES SDR rendering in one CUDA pass; ACES 2.0 uses its fixed 100-nit Rec.709 algorithm table. BT.2408 selects direct mapping to Rec.2020 with HLG or PQ and places SDR reference white at 203 cd/m². All ACES tonemaps accept exactly the two output pairs Rec.709 / BT.1886 and sRGB / sRGB. Both output_colorspace and output_gamma must be supplied explicitly whenever a tonemap is selected. The analytic runtime does not use OCIO or RGB-grid LUT data. ACES 2.0 reproduces its reference-internal output range before display encoding; no tonemap path adds a post-render clip.

S-Log / S-Log2 / S-Log3 apply their lower linear branches directly to signed inputs. For S-Log and S-Log2, public scene-linear reflectance uses x = r / 0.9 and Sony encoded IRE uses the public embedding e = (64 + 876 * y) / 1023. S-Log3 / ARRI-LogC4 do not use sign/magnitude mirroring; ARRI-LogC4 retains its negative scene cut. Established S-Log3 and ARRI-LogC4 results for nonnegative inputs remain float32 bit-identical. ARRI-LogC3 is the ARRI EI 800 relative scene-exposure curve, maps 18% gray to 400 / 1023, and extends its lower linear branch to negative values without clipping or sign/magnitude mirroring. Blackmagic Film Gen 5 uses its published natural-log branches. DaVinci Intermediate uses its published base-2 branches and a derived decode threshold. Both apply their lower linear branches directly to negative values and remain independent from the Blackmagic Wide Gamut Gen 5 and DaVinci Wide Gamut colorspaces. RED-Log3G10 uses RED's published piecewise base-10 curve, applies its lower linear branch directly below -0.01, and leaves scene overshoot unclipped. REDlogFilm uses the Cineon sign-preserving mirror and exact float32 transfer bits while retaining independent gamma metadata. All RED colorspaces remain independent from transfer selection. Canon-Log, Canon-Log-2, and Canon-Log-3 map public reflectance with x = r / 0.9 and apply Canon's 2018 signed branches directly without clipping or sign/magnitude mirroring. Canon-Log-3 includes x = +/-0.014 in its linear branch and derives both decode thresholds from that branch. Canon-Cinema-Gamut uses its published primaries and D65 white, the shared Bradford adaptation path, and remains independent from transfer selection. V-Log applies Panasonic's logarithmic branch directly to reflectance, with a tangent-derived lower branch and decode threshold, without clipping or sign/magnitude mirroring. V-Gamut uses Panasonic's published primaries and D65 white through the shared Bradford adaptation path and remains independent from transfer selection. D-Log, F-Log, and F-Log2 apply their published linear and logarithmic branches directly to reflectance, using the maximum-real-root intersection and its independently rounded encoded value as their cuts. D-Gamut and F-Gamut-C use published primaries with D65 through the shared Bradford path. Transfer and colorspace selection remain independent, equality belongs to the logarithmic branches, and signed and overshoot values remain unclipped. N-Log uses the maximum-real-root intersection and signed cube-root extension. L-Log keeps its printed logarithmic branch and uses the tangent at the printed input cut for its lower branch. Apple-Log preserves the published R0 and encoded-zero collapse, while Samsung-Log extends its continuity-derived lower logarithmic branch without codec clipping. These four transfers take reflectance directly and remain independent from colorspace. Apple-Wide-Gamut uses its published primaries with D65, derives native luma from the normalized primary matrix, and uses the shared Bradford path for differing whites; Apple Log 2 is expressed by selecting it with Apple-Log rather than by a combined token. P3-DCI, P3-D60, and P3-D65 share P3 primaries with DCI, ACES, and D65 white respectively; SMPTE-C uses its H.273 primaries and D65. Their normalized primary matrices, native luma rows, and differing-white Bradford adaptation use the shared colorspace path. Transfer remains independent: Display P3 is expressed with P3-D65 and sRGB, while the Academy AP1 grading combinations use ACEScg with ACEScc or ACEScct. Gamma-2.5 is sign-preserving pure power. ACEScc applies the Academy three-branch analytic encode, including its many-to-one nonpositive collapse, and ACEScct applies the Academy linear toe and log branch. Both take the scene-linear component directly, add no gamut transform or LUT, and analytically extend decode above linear 65504 without an upper clip.

chromatic_adaptation(frame, *, input_white, output_white, cat='CAT02')

Adapt a float32 RGB Frame between explicit CIE 1931 xy white points.

The Frame transfer is decoded, the selected CAT is composed through the Frame colorspace, and the original transfer is encoded in one GPU pass. RGB channels are label-driven; all other channels are copied bit-for-bit.

white_balance(frame, *, temperature, tint=0.0, cat='CAT02')

Correct a source illuminant described by Kelvin and signed raw Duv.

The target is the Frame colorspace's nominal white. Positive Tint describes a source on the green side of the DNG black-body locus and therefore moves the corrected output toward magenta.

white_point_simulation(frame, *, input_white=None, output_white)

Physically re-encode absolute colorimetry between display whites.

The input and output devices use the Frame colorspace primaries normalized to their respective white points. The Frame transfer is decoded, the absolute device matrix is applied, and the original transfer is encoded in one GPU pass. This operation does not perform chromatic adaptation.