74#define UNBOUND_SHADOWS_L UNBOUND_L
75#define UNBOUND_SHADOWS_A UNBOUND_A
76#define UNBOUND_SHADOWS_B UNBOUND_B
77#define UNBOUND_HIGHLIGHTS_L (UNBOUND_L << 3)
78#define UNBOUND_HIGHLIGHTS_A (UNBOUND_A << 3)
79#define UNBOUND_HIGHLIGHTS_B (UNBOUND_B << 3)
80#define UNBOUND_GAUSSIAN 64
81#define UNBOUND_BILATERAL 128
82#define UNBOUND_DEFAULT \
83 (UNBOUND_SHADOWS_L | UNBOUND_SHADOWS_A | UNBOUND_SHADOWS_B | UNBOUND_HIGHLIGHTS_L | UNBOUND_HIGHLIGHTS_A \
84 | UNBOUND_HIGHLIGHTS_B | UNBOUND_GAUSSIAN)
194 return _(
"shadows and highlights");
215 "of an image by enhancing local contrast."),
216 _(
"corrective and creative"),
217 _(
"linear or non-linear, Lab, display-referred"),
218 _(
"non-linear, Lab"),
219 _(
"non-linear, Lab, display-referred"));
223 void *new_params,
const int new_version)
225 if(old_version == 1 && new_version == 5)
230 new->radius = fabs(old->
radius);
231 new->shadows = 0.5f * old->
shadows;
237 new->shadows_ccorrect = 100.0f;
238 new->highlights_ccorrect = 0.0f;
239 new->low_approximation = 0.01f;
243 else if(old_version == 2 && new_version == 5)
248 new->radius = fabs(old->
radius);
257 new->low_approximation = 0.01f;
261 else if(old_version == 3 && new_version == 5)
266 new->radius = fabs(old->
radius);
274 new->flags = old->
flags;
275 new->low_approximation = 0.01f;
279 else if(old_version == 4 && new_version == 5)
284 new->radius = fabs(old->
radius);
292 new->flags = old->
flags;
303 o[0] =
i[0] / 100.0f;
304 o[1] =
i[1] / 128.0f;
305 o[2] =
i[2] / 128.0f;
311 o[0] =
i[0] * 100.0f;
312 o[1] =
i[1] * 128.0f;
313 o[2] =
i[2] * 128.0f;
318 return (
x < 0 ? -1.0f : 1.0f);
327 const float *
const restrict in = (
float *)ivoid;
328 float *
const restrict
out = (
float *)
ovoid;
333 const int order = data->order;
334 const float radius = fmaxf(0.1f, data->radius);
336 const float shadows = 2.0f * fmin(fmax(-1.0, (data->shadows / 100.0f)), 1.0f);
337 const float highlights = 2.0f * fmin(fmax(-1.0, (data->highlights / 100.0f)), 1.0f);
338 const float whitepoint = fmax(1.0f - data->whitepoint / 100.0f, 0.01f);
340 = fmin(fmax(0, (data->compress / 100.0f)), 0.99f);
341 const float shadows_ccorrect = (fmin(fmax(0.0f, (data->shadows_ccorrect / 100.0f)), 1.0f) - 0.5f)
342 *
sign(shadows) + 0.5f;
343 const float highlights_ccorrect = (fmin(fmax(0.0f, (data->highlights_ccorrect / 100.0f)), 1.0f) - 0.5f)
344 *
sign(-highlights) + 0.5f;
345 const unsigned int flags = data->flags;
348 const float low_approximation = data->low_approximation;
357 for(
int k = 0;
k < 4;
k++) Labmax[
k] = INFINITY;
358 for(
int k = 0;
k < 4;
k++) Labmin[
k] = -INFINITY;
370 const float detail = -1.0f;
382 const float lmin = 0.0f;
383 const float lmax =
max[0] + fabsf(
min[0]);
384 const float halfmax = lmax / 2.0;
385 const float doublemax = lmax * 2.0;
392 out[j + 0] = 100.0f -
out[j + 0];
397 ta[0] = ta[0] > 0.0f ? ta[0] / whitepoint : ta[0];
398 tb[0] = tb[0] > 0.0f ? tb[0] / whitepoint : tb[0];
401 float highlights2 = highlights * highlights;
402 const float highlights_xform = CLAMP(1.0f - tb[0] / (1.0f - compress), 0.0f, 1.0f);
404 while(highlights2 > 0.0f)
407 float lb = (tb[0] - halfmax) *
sign(-highlights) *
sign(lmax - la) + halfmax;
408 lb = unbound_mask ? lb : CLAMP(lb, lmin, lmax);
409 const float lref = copysignf(fabsf(la) > low_approximation ? 1.0f / fabsf(la) : 1.0f / low_approximation, la);
410 const float href = copysignf(
411 fabsf(1.0f - la) > low_approximation ? 1.0f / fabsf(1.0f - la) : 1.0f / low_approximation, 1.0f - la);
413 const float chunk = highlights2 > 1.0f ? 1.0f : highlights2;
414 const float optrans = chunk * highlights_xform;
417 ta[0] = la * (1.0 - optrans)
418 + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax - lb) : doublemax * la
423 const float chroma_factor = (ta[0] * lref * (1.0f - highlights_ccorrect)
424 + (1.0f - ta[0]) * href * highlights_ccorrect);
425 ta[1] = ta[1] * (1.0f - optrans) + (ta[1] + tb[1]) * chroma_factor * optrans;
428 ta[2] = ta[2] * (1.0f - optrans) + (ta[2] + tb[2]) * chroma_factor * optrans;
433 float shadows2 = shadows * shadows;
434 const float shadows_xform = CLAMP(tb[0] / (1.0f - compress) - compress / (1.0f - compress), 0.0f, 1.0f);
436 while(shadows2 > 0.0f)
439 float lb = (tb[0] - halfmax) *
sign(shadows) *
sign(lmax - la) + halfmax;
440 lb = unbound_mask ? lb : CLAMP(lb, lmin, lmax);
441 const float lref = copysignf(fabsf(la) > low_approximation ? 1.0f / fabsf(la) : 1.0f / low_approximation, la);
442 const float href = copysignf(
443 fabsf(1.0f - la) > low_approximation ? 1.0f / fabsf(1.0f - la) : 1.0f / low_approximation, 1.0f - la);
446 const float chunk = shadows2 > 1.0f ? 1.0f : shadows2;
447 const float optrans = chunk * shadows_xform;
450 ta[0] = la * (1.0 - optrans)
451 + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax - lb) : doublemax * la
456 const float chroma_factor = (ta[0] * lref * shadows_ccorrect
457 + (1.0f - ta[0]) * href * (1.0f - shadows_ccorrect));
458 ta[1] = ta[1] * (1.0f - optrans) + (ta[1] + tb[1]) * chroma_factor * optrans;
461 ta[2] = ta[2] * (1.0f - optrans) + (ta[2] + tb[2]) * chroma_factor * optrans;
484 const float radius = fmax(0.1f,
d->radius);
489 const size_t basebuffer =
sizeof(float) * channels *
width *
height;
519 d->radius =
p->radius;
520 d->shadows =
p->shadows;
521 d->highlights =
p->highlights;
522 d->whitepoint =
p->whitepoint;
523 d->compress =
p->compress;
524 d->shadows_ccorrect =
p->shadows_ccorrect;
525 d->highlights_ccorrect =
p->highlights_ccorrect;
527 d->low_approximation =
p->low_approximation;
528 d->shadhi_algo =
p->shadhi_algo;
559 gtk_widget_set_tooltip_text(
g->shadows, _(
"correct shadows"));
560 gtk_widget_set_tooltip_text(
g->highlights, _(
"correct highlights"));
561 gtk_widget_set_tooltip_text(
g->whitepoint, _(
"shift white point"));
562 gtk_widget_set_tooltip_text(
g->radius, _(
"spatial extent"));
563 gtk_widget_set_tooltip_text(
g->shadhi_algo, _(
"filter to use for softening. bilateral avoids halos"));
564 gtk_widget_set_tooltip_text(
g->compress, _(
"compress the effect on shadows/highlights and\npreserve mid-tones"));
565 gtk_widget_set_tooltip_text(
g->shadows_ccorrect, _(
"adjust saturation of shadows"));
566 gtk_widget_set_tooltip_text(
g->highlights_ccorrect, _(
"adjust saturation of highlights"));
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
void dt_bilateral_free(dt_bilateral_t *b)
__DT_CLONE_TARGETS__ void dt_bilateral_splat(const dt_bilateral_t *b, const float *const in)
size_t dt_bilateral_memory_use(const int width, const int height, const float sigma_s, const float sigma_r)
dt_bilateral_t * dt_bilateral_init(const int width, const int height, const float sigma_s, const float sigma_r)
size_t dt_bilateral_singlebuffer_size(const int width, const int height, const float sigma_s, const float sigma_r)
__DT_CLONE_TARGETS__ void dt_bilateral_slice(const dt_bilateral_t *const b, const float *const in, float *out, const float detail)
void dt_bilateral_blur(const dt_bilateral_t *b)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
static const float const float const float min
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
static const dt_aligned_pixel_simd_t sign
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
void dt_gaussian_free(dt_gaussian_t *g)
size_t dt_gaussian_singlebuffer_size(const int width, const int height, const int channels)
void dt_gaussian_blur_4c(dt_gaussian_t *g, const float *const in, float *const out)
dt_gaussian_t * dt_gaussian_init(const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
size_t dt_gaussian_memory_use(const int width, const int height, const int channels)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
float dt_aligned_pixel_t[4]
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
#define UNBOUND_SHADOWS_L
const char ** description(struct dt_iop_module_t *self)
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
#define UNBOUND_HIGHLIGHTS_L
#define UNBOUND_HIGHLIGHTS_A
#define UNBOUND_SHADOWS_A
#define UNBOUND_SHADOWS_B
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void gui_init(struct dt_iop_module_t *self)
static void _Lab_rescale(const float *i, float *o)
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
#define UNBOUND_BILATERAL
#define UNBOUND_HIGHLIGHTS_B
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void _Lab_scale(const float *i, float *o)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
struct _GtkWidget GtkWidget
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
Region of interest passed through the pixelpipe.
dt_gaussian_order_t order
float highlights_ccorrect
dt_iop_shadhi_algo_t shadhi_algo
GtkWidget * highlights_ccorrect
GtkWidget * shadows_ccorrect
dt_gaussian_order_t order
dt_gaussian_order_t order
float highlights_ccorrect
float highlights_ccorrect
dt_gaussian_order_t order
float highlights_ccorrect
dt_gaussian_order_t order
dt_gaussian_order_t order
dt_iop_shadhi_algo_t shadhi_algo
float highlights_ccorrect