Files
RecipesCam/src/utils/paramDefs.ts
T
admin 28e18893cd Add HDF (Highlight Diffusion Filter) to the FX tab
The built-in lens filter, simulated the way it is done in Photoshop: pull the
highlights out with a hard contrast curve (out = 2.5*in - 1.5, black below 0.6),
Gaussian-blur that selection, then Screen it back over the photo at reduced
opacity. Screen against a near-black pixel is a no-op, so areas with no
highlight within the blur radius come back byte-identical while lit areas
spread their light.

One 0..10 knob drives both the radius (4%..1.9% of the width, ~10..50px at
2560 wide) and the opacity (0.15..0.5), matching the recipe's 15-50px radius
range. The extraction composes on top of the recipe colour matrix so a
monochrome look glows white instead of leaking the original colours back.

Runs in the Skia export engine only; the P5 native path is not wired into the
app (dev parity probe only), so it is left alone for now.
2026-09-10 09:45:51 +07:00

177 lines
3.7 KiB
TypeScript

import { ColorAdjustments } from '../types';
// Static metadata for the continuous (slider) adjustments of the IQ/WB/FILTERS
// tabs — shared between AdjustmentPanel (chips + slider rows) and App (which
// needs the open row's bounds to drive drag-on-the-image adjustment). The get
// /set accessors are stateless so one table serves every render.
export interface ContinuousParamDef {
key: string;
label: string;
min: number;
max: number;
step: number;
defaultValue: number;
display: (v: number) => string;
get: (a: ColorAdjustments) => number;
set: (v: number) => Partial<ColorAdjustments>;
}
const sign = (v: number) => (v > 0 ? `+${v}` : String(v));
const oneEv = (v: number) => `${v > 0 ? '+' : ''}${v.toFixed(1)} EV`;
export const PARAM_DEFS: {
iq: ContinuousParamDef[];
wb: ContinuousParamDef[];
filters: ContinuousParamDef[];
} = {
iq: [
{
key: 'exposure',
label: 'EXPOSURE',
min: -10,
max: 10,
step: 1,
defaultValue: 0,
display: sign,
get: (a) => a.exposure,
set: (v) => ({ exposure: v }),
},
{
key: 'ev',
label: 'EV',
min: -3,
max: 3,
step: 0.5,
defaultValue: 0,
display: oneEv,
get: (a) => a.exposureCompensation ?? 0,
set: (v) => ({ exposureCompensation: v }),
},
{
key: 'contrast',
label: 'CONTRAST',
min: -10,
max: 10,
step: 1,
defaultValue: 0,
display: sign,
get: (a) => a.contrast,
set: (v) => ({ contrast: v }),
},
{
key: 'color',
label: 'COLOR',
min: -10,
max: 10,
step: 1,
defaultValue: 0,
display: sign,
get: (a) => a.saturation,
set: (v) => ({ saturation: v }),
},
{
key: 'highlight',
label: 'HIGHLIGHT',
min: -10,
max: 10,
step: 1,
defaultValue: 0,
display: sign,
get: (a) => a.highlight ?? 0,
set: (v) => ({ highlight: v }),
},
{
key: 'shadow',
label: 'SHADOW',
min: -10,
max: 10,
step: 1,
defaultValue: 0,
display: sign,
get: (a) => a.shadow ?? 0,
set: (v) => ({ shadow: v }),
},
],
wb: [
{
key: 'temperature',
label: 'COLOR TEMP',
min: 2500,
max: 10000,
step: 100,
defaultValue: 5500,
display: (v) => `${v}K`,
get: (a) => a.temperature,
set: (v) => ({ temperature: v }),
},
{
key: 'tint',
label: 'TINT',
min: -10,
max: 10,
step: 1,
defaultValue: 0,
display: sign,
get: (a) => a.tint ?? 0,
set: (v) => ({ tint: v }),
},
],
filters: [
{
key: 'denoise',
label: 'NOISE REDUCTION',
min: 0,
max: 10,
step: 1,
defaultValue: 0,
display: String,
get: (a) => a.denoise,
set: (v) => ({ denoise: v }),
},
{
key: 'clarity',
label: 'CLARITY',
min: -10,
max: 10,
step: 1,
defaultValue: 0,
display: sign,
get: (a) => a.clarity,
set: (v) => ({ clarity: v }),
},
{
key: 'sharpening',
label: 'SHARPENING',
min: 0,
max: 10,
step: 1,
defaultValue: 0,
display: String,
get: (a) => a.sharpening ?? 0,
set: (v) => ({ sharpening: v }),
},
{
key: 'grain',
label: 'MONOCHROME GRAIN',
min: 0,
max: 10,
step: 1,
defaultValue: 0,
display: String,
get: (a) => a.grain,
set: (v) => ({ grain: v }),
},
{
key: 'hdf',
label: 'HDF',
min: 0,
max: 10,
step: 1,
defaultValue: 0,
display: String,
get: (a) => a.hdf ?? 0,
set: (v) => ({ hdf: v }),
},
],
};