light: AUTO and the shipped recipes ride the halved knobs too — AUTO's ceiling doubles with them so a blown frame still comes back the way it did, and each recipe's HIGHLIGHT/SHADOW doubles so its look stays on the knot it was tuned to
This commit is contained in:
@@ -62,28 +62,28 @@ assert.equal(Math.round(stops(spike(87)) * 10) / 10, 0.5, 'a dark frame is asked
|
||||
assert.ok(Math.abs(stops(flat()) + 0.0589) < 5e-4, 'a flat ramp sits just under mid-grey');
|
||||
assert.equal(stops(spike(20, 0)), AUTO_EV_MAX, 'an empty histogram takes the ceiling, not infinity');
|
||||
|
||||
// --- Highlight / Shadow: the 1% tails, thresholds 0.9 / 0.02, ramp to ±5.
|
||||
assert.deepEqual(autoTone(spike(255)), { highlight: -5, shadow: 0 }, 'blown frame only pulls highlights');
|
||||
assert.deepEqual(autoTone(spike(0)), { highlight: 0, shadow: 5 }, 'black frame only opens shadows');
|
||||
// --- Highlight / Shadow: the 1% tails, thresholds 0.9 / 0.02, ramp to ±10.
|
||||
assert.deepEqual(autoTone(spike(255)), { highlight: -10, shadow: 0 }, 'blown frame only pulls highlights');
|
||||
assert.deepEqual(autoTone(spike(0)), { highlight: 0, shadow: 10 }, 'black frame only opens shadows');
|
||||
// The flat ramp is the interesting one: its own top 1% really is clipped and its
|
||||
// own bottom 1% really is on the floor, so both ends move. p99 = 253/255 = 0.992
|
||||
// (5 units), p01 = 2/255 = 0.008 (3 units).
|
||||
assert.deepEqual(autoTone(flat()), { highlight: -5, shadow: 3 }, 'an even ramp has both ends in play');
|
||||
// (9 units), p01 = 2/255 = 0.008 (6 units).
|
||||
assert.deepEqual(autoTone(flat()), { highlight: -9, shadow: 6 }, 'an even ramp has both ends in play');
|
||||
// 1% of the frame at white over an otherwise mid ramp: the spec's small blown
|
||||
// window, and the shadow side stays put because the ramp's floor is not black.
|
||||
const blown = flat();
|
||||
blown[255] += 3;
|
||||
assert.deepEqual(autoTone(blown), { highlight: -5, shadow: 3 }, 'a blown 1% is enough to pull the top');
|
||||
assert.deepEqual(autoTone(blown), { highlight: -10, shadow: 6 }, 'a blown 1% is enough to pull the top');
|
||||
// p99 landed just over the threshold: 989 pixels mid-ramp and 11 at bin 243 puts
|
||||
// p99 at 0.953, 0.053 over 0.9 -> 2.65 units -> 3. Proof the pull is graded.
|
||||
// p99 at 0.953, 0.053 over 0.9 -> 5.3 units -> 5. Proof the pull is graded.
|
||||
const shoulder = spike(100, 989);
|
||||
shoulder[243] = 11;
|
||||
assert.deepEqual(autoTone(shoulder), { highlight: -3, shadow: 0 }, 'p99 just over 0.9 pulls a third of the way');
|
||||
assert.deepEqual(autoTone(shoulder), { highlight: -5, shadow: 0 }, 'p99 just over 0.9 pulls half the way');
|
||||
// 2% of pixels two bins off the floor: p01 = 0.008, so the shadow side moves —
|
||||
// but only 3 units, because the tail is barely under the 0.02 threshold.
|
||||
// but only 6 units, because the tail is barely under the 0.02 threshold.
|
||||
const crushed = spike(128, 980);
|
||||
crushed[2] = 20;
|
||||
assert.deepEqual(autoTone(crushed), { highlight: 0, shadow: 3 }, 'a crushed 2% opens the shadows part way');
|
||||
assert.deepEqual(autoTone(crushed), { highlight: 0, shadow: 6 }, 'a crushed 2% opens the shadows part way');
|
||||
// 0.4% on the floor is NOT the bottom 1%: the tenth-darkest pixel is the mid
|
||||
// ramp, so the threshold is not crossed and the knob stays put.
|
||||
const speck = spike(128, 996);
|
||||
|
||||
Reference in New Issue
Block a user