Skip to main content

Crate zentone

Crate zentone 

Source
Expand description

HDR → SDR tone mapping curves in safe Rust.

zentone is a library of tone-mapping curves — the math that compresses HDR luminance into an SDR display range. It is not a full color management pipeline: linearization, primary conversion, OETF encoding, and ICC handling live in linear-srgb and zenpixels-convert. Use zentone when you have linear-light HDR samples and need to choose a curve.

no_std + alloc, zero allocation in hot paths, SIMD-accelerated on x86-64 (AVX2+FMA) with scalar fallback everywhere else.

§API tiers

The public surface splits into three tiers; pick by workload, not by name recognition.

As of 0.2.0, the pipeline ships SIMD strip-form APIs only — the old &[f32] + channels: u8 forms are not present. See CHANGELOG.md for the removal record.

§What’s in the box

Curves come in four families. Each implements the ToneMap trait; pick by use case, not by name.

  • Classical, statelessToneMapCurve: simple Reinhard (x/(1+x)), extended Reinhard with white point, Reinhard-Jodie, tuned Reinhard (display-aware nits), Narkowicz, Hable, ACES AP1, AgX (Blender) with Default/Punchy/Golden looks, BT.2390 EETF, and Clamp. No state, no allocation, SIMD-accelerated row paths.
  • ITU broadcast standardsBt2408Tonemapper (BT.2408 Annex 5 PQ-domain Hermite spline, YRGB or MaxRGB), Bt2446A / Bt2446B / Bt2446C (BT.2446 Methods A, B, C). Constructed once with (content_max_nits, display_max_nits).
  • Filmic splineCompiledFilmicSpline / FilmicSplineConfig: darktable / Blender-style rational spline with toe / linear / shoulder regions and per-pixel highlight desaturation. Heavy parameter surface for calibrated workflows.
  • Gain map splitter (gainmap) — round-trippable HDR ↔ (SDR, log2 gain) splitter for ISO 21496-1 / Apple Ultra HDR encoders, plus companion LumaToneMap curve impls (Bt2408Yrgb, ExtendedReinhardLuma, HableFilmic) and PQ/HLG row helpers.
  • Experimental (behind the experimental feature) — adaptive LUT fitting, single-pass streaming tonemap with local adaptation, DNG ProfileToneCurve.

§Quick start

Every tonemapper takes a linear-light RGB triple and returns linear SDR RGB. Wire format decoding (PQ / HLG / sRGB) and primary conversion happen before / after.

use zentone::{Bt2446C, ToneMap};

// 1000 cd/m² HDR content → 203 cd/m² SDR (HDR Reference White).
// Input scale: 1.0 = hdr_peak_nits; output scale: 1.0 = sdr_peak_nits.
let curve = Bt2446C::new(1000.0, 203.0);
let sdr = curve.map_rgb([2.0, 1.0, 0.5]);
assert!(sdr.iter().all(|&c| c.is_finite() && c >= 0.0));

For an entire row, use map_row (in place) or map_into (separate dst). Both dispatch on channels (3 = RGB, 4 = RGBA, alpha preserved):

use zentone::{ToneMap, ToneMapCurve};
let mut row = [0.5_f32, 1.2, 0.3, 0.8, 2.0, 0.1];
ToneMapCurve::Narkowicz.map_row(&mut row, 3);

For a fused PQ→tone-map→sRGB-gamut pipeline on a packed strip (the canonical hot-path shape):

use zentone::{Bt2446C, TonemapScratch, pipeline::tonemap_pq_row_simd};

// 1024 PQ-encoded BT.2020 RGB pixels — 0.58 ≈ HDR Reference White.
let pq = vec![[0.58_f32, 0.58, 0.58]; 1024];
let mut out = vec![[0.0_f32; 3]; 1024];
let curve = Bt2446C::new(1000.0, 203.0);
let mut scratch = TonemapScratch::new();
tonemap_pq_row_simd(&mut scratch, &pq, &mut out, &curve);

§Choosing a curve

NeedPick
“Just give me something cheap and decent”ToneMapCurve::Narkowicz or HableFilmic
Game engine / shader portToneMapCurve::AcesAp1 or Agx
Broadcast-grade HDR10 / HLG → SDR with display peak nitsBt2408Tonemapper (PQ-domain) or Bt2446A
Live HLG → SDR, conservative on clipped highlightsBt2446B
HDR → SDR with mathematical inverse (round-trip / detection)Bt2446C
Calibrated photo workflow with toe / shoulder controlCompiledFilmicSpline
ISO 21496-1 / Ultra HDR gain map encoderLumaGainMapSplitter
Re-derive a curve from an HDR/SDR reference pairexperimental::AdaptiveTonemapper

Curves that need RGB→Y weights take them at construction time via LUMA_BT709, LUMA_BT2020, or LUMA_P3. Pick the one that matches the input primaries — passing BT.709 weights for BT.2020 input over-desaturates greens.

§Tone mapping vs gain map splitting

Two adjacent but distinct contracts live in this crate.

Most curves implement both traits — Bt2408Yrgb, Bt2446A/B/C, ExtendedReinhardLuma, CompiledFilmicSpline, and HableFilmic all derive LumaToneMap from their luma response. The splitter’s LumaToneMap is luma-only because chromaticity preservation requires applying a scalar curve to luma and then rescaling the RGB triple — per-channel and matrix-based ToneMap curves do not have a coherent luma-only interpretation, so they are intentionally not adapted.

See src/gainmap.rs for the splitter; see src/pipeline.rs for the tone-map row kernels.

§Utility modules

§Experimental (experimental feature)

Behind a feature flag because the APIs are still in flux:

  • experimental::AdaptiveTonemapper — fits a LUT from an HDR/SDR pair.
  • experimental::StreamingTonemapper — single-pass spatially-local tonemap with bounded-memory pull API.
  • experimental::ProfileToneCurve — DNG camera-profile tone curve; per-channel or luminance-preserving views via ToneMap.
  • experimental::detect::detect_standard — identifies which standard curve was applied to a fitted LUT.

Lightly tested; API may change without semver bumps until stabilized. See the experimental module docs when the feature is enabled.

Re-exports§

pub use curves::AgxLook;
pub use curves::ToneMapCurve;
pub use gainmap::Bt2408Yrgb;
pub use gainmap::ExtendedReinhardLuma;
pub use gainmap::HableFilmic;
pub use gainmap::LumaFn;
pub use gainmap::LumaGainMapSplitter;
pub use gainmap::LumaToneMap;
pub use gainmap::SplitConfig;
pub use gainmap::SplitStats;

Modules§

curves
Classical tone mapping curves and unified ToneMapCurve dispatch.
gainmap
Luma gain map splitter — round-trippable HDR ↔ (SDR, log2 gain).
gamut
Color gamut conversion and soft clipping.
hlg
HLG system gamma, OOTF, and display adaptation.
pipeline
HDR → SDR pipeline helpers.
sdr_hdr
Display-referred SDR↔HDR signal-level conversion utilities.

Structs§

Bt2408Tonemapper
BT.2408 tone mapper operating in PQ perceptual domain.
Bt2446A
BT.2446 Method A tonemapper.
Bt2446B
BT.2446 Method B simplified HLG tonemapper.
Bt2446C
BT.2446 Method C tonemapper.
CompiledFilmicSpline
Compiled filmic spline (precomputed from FilmicSplineConfig).
FilmicSplineConfig
Filmic spline configuration parameters.
TonemapScratch
Reusable scratch buffers + chunk-size policy for the SIMD tone-map pipelines.

Enums§

EetfSpace
Color space in which the EETF tone mapping is applied.
Error
Errors produced by zentone.

Constants§

LUMA_BT709
BT.709 / sRGB luminance coefficients [0.2126, 0.7152, 0.0722].
LUMA_BT2020
BT.2020 luminance coefficients [0.2627, 0.6780, 0.0593].
LUMA_P3
Display-P3 / DCI-P3 luminance coefficients [0.2289746, 0.6917385, 0.0792869].

Traits§

ToneMap
A linear-light RGB tonemapper.

Type Aliases§

Result
Result alias for zentone.