The field documents "1 = neutral; lower = more contrast", but the tone map used gamma directly as the powf exponent, so 0.5 lightened midtones and 2.0 darkened them - the slider ran opposite to its own contract. The crate's other two gamma controls (hdr.rs, proof_sim.rs) already use the reciprocal exponent. Apply 1.0 / gamma like they do. Neutral (1.0) is unchanged; every other value now moves midtones the documented way. Adds a regression test on a flat 50% grey: gamma 0.5 darkens the midtone, gamma 2.0 lightens it (reversed on main: 0.71 / 0.25). Co-authored-by: Brandon Fenty <bfenty@users.noreply.github.com>
This commit is contained in:
parent
080f2c4c8d
commit
385e8979de
|
|
@ -343,7 +343,9 @@ pub fn hdr_toning(px: &mut [[f32; 4]], w: usize, h: usize, p: &HdrToning) {
|
|||
let c = [q[0], q[1], q[2]];
|
||||
let l0 = luma(c).max(0.0) + EPS;
|
||||
let new_log = mean + (base[i] - mean) * compress + (logl[i] - base[i]) * detail;
|
||||
let mut l1 = (new_log.exp() * exposure).max(0.0).powf(gamma);
|
||||
// The contract is "lower = more contrast", i.e. gamma is the divisor of
|
||||
// the exponent, matching the crate's other gamma controls (hdr.rs, proof_sim.rs).
|
||||
let mut l1 = (new_log.exp() * exposure).max(0.0).powf(1.0 / gamma);
|
||||
l1 += p.shadow / 100.0 * (1.0 - l1).powi(3) * 0.5 - p.highlight / 100.0 * l1.powi(3) * 0.5;
|
||||
l1 = curve_eval(&sorted, l1.clamp(0.0, 1.0));
|
||||
let ratio = l1 / l0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
//! Regression tests for issue #710: HdrToning gamma is documented as
|
||||
//! "1 = neutral; lower = more contrast", so a gamma below 1 must darken
|
||||
//! midtones (like the crate's other gamma controls, which use 1/gamma as the
|
||||
//! exponent). On main the value was used directly as the exponent, so the
|
||||
//! slider ran opposite to its contract.
|
||||
use photocraft_engine::Session;
|
||||
use serde_json::json;
|
||||
|
||||
fn midtone_luma(gamma: f64) -> f64 {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", json!({"width": 8, "height": 8, "background": "#808080"})).unwrap();
|
||||
s.execute(
|
||||
"image.adjustments.hdrToning",
|
||||
json!({"gamma": gamma, "strength": 0.1, "detail": 0, "saturation": 0, "radius": 30}),
|
||||
)
|
||||
.unwrap();
|
||||
let p: Vec<f32> = serde_json::from_value(s.execute("document.pixel", json!({"x": 4, "y": 4})).unwrap()).unwrap();
|
||||
f64::from(0.299 * p[0] + 0.587 * p[1] + 0.114 * p[2])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hdr_toning_gamma_lower_darkens_midtones() {
|
||||
let base = midtone_luma(1.0);
|
||||
let low = midtone_luma(0.5);
|
||||
let high = midtone_luma(2.0);
|
||||
// "lower = more contrast" on a mid grey means the midtone moves down.
|
||||
assert!(low < base, "gamma 0.5 must darken the midtone: base={base} low={low}");
|
||||
assert!(high > base, "gamma 2.0 must lighten the midtone: base={base} high={high}");
|
||||
}
|
||||
Loading…
Reference in New Issue