Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
exposure.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2016, 2018 johannes hanika.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2012 Henrik Andersson.
6 Copyright (C) 2010 José Carlos García Sogo.
7 Copyright (C) 2010 Milan Knížek.
8 Copyright (C) 2010 Stuart Henderson.
9 Copyright (C) 2011 Antony Dovgal.
10 Copyright (C) 2011 Christophe Augier.
11 Copyright (C) 2011 Olivier Tribout.
12 Copyright (C) 2011-2012 Pascal de Bruijn.
13 Copyright (C) 2011 Robert Bieber.
14 Copyright (C) 2011 root.
15 Copyright (C) 2011-2019 Tobias Ellinghaus.
16 Copyright (C) 2011-2014, 2017 Ulrich Pegelow.
17 Copyright (C) 2012 Edouard Gomez.
18 Copyright (C) 2012 Richard Wonka.
19 Copyright (C) 2013, 2020, 2022 Aldric Renaudin.
20 Copyright (C) 2013 Dennis Gnad.
21 Copyright (C) 2013-2014, 2018-2022 Pascal Obry.
22 Copyright (C) 2014-2016 Roman Lebedev.
23 Copyright (C) 2015 Jan Kundrát.
24 Copyright (C) 2015 Pedro Côrte-Real.
25 Copyright (C) 2016 Alexander V. Smal.
26 Copyright (C) 2017 Heiko Bauke.
27 Copyright (C) 2018-2023, 2025-2026 Aurélien PIERRE.
28 Copyright (C) 2018-2019 Edgardo Hoszowski.
29 Copyright (C) 2018 Maurizio Paglia.
30 Copyright (C) 2018 rawfiner.
31 Copyright (C) 2019 Andreas Schneider.
32 Copyright (C) 2019-2020, 2022 Diederik Ter Rahe.
33 Copyright (C) 2020-2022 Chris Elston.
34 Copyright (C) 2020 Ralf Brown.
35 Copyright (C) 2021 Alex Esseling.
36 Copyright (C) 2021 Hubert Kowalski.
37 Copyright (C) 2022 Hanno Schwalm.
38 Copyright (C) 2022 Martin Bařinka.
39 Copyright (C) 2022 Philipp Lutz.
40 Copyright (C) 2023 Luca Zulberti.
41 Copyright (C) 2025 Guillaume Stutin.
42
43 darktable is free software: you can redistribute it and/or modify
44 it under the terms of the GNU General Public License as published by
45 the Free Software Foundation, either version 3 of the License, or
46 (at your option) any later version.
47
48 darktable is distributed in the hope that it will be useful,
49 but WITHOUT ANY WARRANTY; without even the implied warranty of
50 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51 GNU General Public License for more details.
52
53 You should have received a copy of the GNU General Public License
54 along with darktable. If not, see <http://www.gnu.org/licenses/>.
55*/
56#ifdef HAVE_CONFIG_H
57#include "config.h"
58#endif
59
60#include <assert.h>
61#include <math.h>
62#include <stdint.h>
63#include <stdlib.h>
64#include <string.h>
65
66#include "bauhaus/bauhaus.h"
67#include "common/darktable.h"
68#include "common/histogram.h"
69#include "common/image_cache.h"
70#include "common/mipmap_cache.h"
71#include "common/opencl.h"
72#include "control/control.h"
73#include "develop/develop.h"
74#include "develop/imageop.h"
76#include "develop/imageop_gui.h"
77#include "develop/pixelpipe.h"
78#include "dtgtk/paint.h"
79#include "dtgtk/resetlabel.h"
80
81#include "gui/gtk.h"
82#include "gui/presets.h"
84#include "iop/iop_api.h"
85
86#define exposure2white(x) exp2f(-(x))
87#define white2exposure(x) -dt_log2f(fmaxf(1e-20f, x))
88
90
92{
93 EXPOSURE_MODE_MANUAL, // $DESCRIPTION: "manual"
94 EXPOSURE_MODE_DEFLICKER // $DESCRIPTION: "automatic"
96
103
104// uint16_t pixel can have any value in range [0, 65535], thus, there is
105// 65536 possible values.
106#define DEFLICKER_BINS_COUNT (UINT16_MAX + 1)
107
108typedef struct dt_iop_exposure_params_t
109{
110 dt_iop_exposure_mode_t mode; // $DEFAULT: EXPOSURE_MODE_MANUAL
111 float black; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: 0.0 $DESCRIPTION: "black level correction"
112 float exposure; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: 0.0
113 float deflicker_percentile; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 50.0 $DESCRIPTION: "percentile"
114 float deflicker_target_level; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: -4.0 $DESCRIPTION: "target level"
115 gboolean compensate_exposure_bias; // $DEFAULT: FALSE $DESCRIPTION: "compensate exposure bias"
117
142
150
155
156
157const char *name()
158{
159 return _("exp_osure");
160}
161
162const char** description(struct dt_iop_module_t *self)
163{
164 return dt_iop_set_description(self,
165 _("redo the exposure of the shot as if you were still in-camera\n"
166 "using a color-safe brightening similar to increasing ISO setting"),
167 _("corrective and creative"),
168 _("linear, RGB, scene-referred"),
169 _("linear, RGB"),
170 _("linear, RGB, scene-referred"));
171}
172
174{
175 return IOP_GROUP_TONES;
176}
177
182
184{
185 return IOP_CS_RGB;
186}
187
188static void _process_common_setup(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe,
189 const dt_dev_pixelpipe_iop_t *piece);
190
193{
194 default_output_format(self, pipe, piece, dsc);
195}
196
197static void _paint_hue(dt_iop_module_t *self);
198static void _exposure_set_black(struct dt_iop_module_t *self, const float black);
199
200int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
201 void *new_params, const int new_version)
202{
203 if(old_version == 2 && new_version == 6)
204 {
205 typedef struct dt_iop_exposure_params_v2_t
206 {
207 float black, exposure, gain;
208 } dt_iop_exposure_params_v2_t;
209
210 dt_iop_exposure_params_v2_t *o = (dt_iop_exposure_params_v2_t *)old_params;
213
214 *n = *d; // start with a fresh copy of default parameters
215
216 n->black = o->black;
217 n->exposure = o->exposure;
218 n->compensate_exposure_bias = FALSE;
219 return 0;
220 }
221 if(old_version == 3 && new_version == 6)
222 {
223 typedef struct dt_iop_exposure_params_v3_t
224 {
225 float black, exposure;
226 gboolean deflicker;
227 float deflicker_percentile, deflicker_target_level;
228 } dt_iop_exposure_params_v3_t;
229
230 dt_iop_exposure_params_v3_t *o = (dt_iop_exposure_params_v3_t *)old_params;
233
234 *n = *d; // start with a fresh copy of default parameters
235
236 n->mode = o->deflicker ? EXPOSURE_MODE_DEFLICKER : EXPOSURE_MODE_MANUAL;
237 n->black = o->black;
238 n->exposure = o->exposure;
239 n->deflicker_percentile = o->deflicker_percentile;
240 n->deflicker_target_level = o->deflicker_target_level;
241 n->compensate_exposure_bias = FALSE;
242 return 0;
243 }
244 if(old_version == 4 && new_version == 6)
245 {
246 typedef enum dt_iop_exposure_deflicker_histogram_source_t {
247 DEFLICKER_HISTOGRAM_SOURCE_THUMBNAIL,
248 DEFLICKER_HISTOGRAM_SOURCE_SOURCEFILE
249 } dt_iop_exposure_deflicker_histogram_source_t;
250
251 typedef struct dt_iop_exposure_params_v4_t
252 {
254 float black;
255 float exposure;
256 float deflicker_percentile, deflicker_target_level;
257 dt_iop_exposure_deflicker_histogram_source_t deflicker_histogram_source;
258 } dt_iop_exposure_params_v4_t;
259
260 dt_iop_exposure_params_v4_t *o = (dt_iop_exposure_params_v4_t *)old_params;
263
264 *n = *d; // start with a fresh copy of default parameters
265
266 n->mode = o->mode;
267 n->black = o->black;
268 n->exposure = o->exposure;
269 n->deflicker_percentile = o->deflicker_percentile;
270 n->deflicker_target_level = o->deflicker_target_level;
271 // deflicker_histogram_source is dropped. this does change output,
272 // but deflicker still was not publicly released at that point
273 n->compensate_exposure_bias = FALSE;
274 return 0;
275 }
276 if(old_version == 5 && new_version == 6)
277 {
278 typedef struct dt_iop_exposure_params_v5_t
279 {
281 float black;
282 float exposure;
283 float deflicker_percentile, deflicker_target_level;
284 } dt_iop_exposure_params_v5_t;
285
286 dt_iop_exposure_params_v5_t *o = (dt_iop_exposure_params_v5_t *)old_params;
289
290 *n = *d; // start with a fresh copy of default parameters
291
292 n->mode = o->mode;
293 n->black = o->black;
294 n->exposure = o->exposure;
295 n->deflicker_percentile = o->deflicker_percentile;
296 n->deflicker_target_level = o->deflicker_target_level;
297 n->compensate_exposure_bias = FALSE;
298 return 0;
299 }
300 return 1;
301}
302
304{
305 dt_gui_presets_add_generic(_("magic lantern defaults"), self->op,
306 self->version(),
307 &(dt_iop_exposure_params_t){.mode = EXPOSURE_MODE_DEFLICKER,
308 .black = 0.0f,
309 .exposure = 0.0f,
310 .deflicker_percentile = 50.0f,
311 .deflicker_target_level = -4.0f,
312 .compensate_exposure_bias = FALSE},
314
315
316 // For scene-referred workflow, since filmic doesn't brighten as base curve does,
317 // we need an initial exposure boost. This might be too much in some cases but...
318 // (the preset name is used in develop.c)
319 dt_gui_presets_add_generic(_("scene-referred default"), self->op, self->version(),
320 &(dt_iop_exposure_params_t){.mode = EXPOSURE_MODE_MANUAL,
321 .black = -0.000244140625f,
322 .exposure = 0.7f,
323 .deflicker_percentile = 50.0f,
324 .deflicker_target_level = -4.0f,
325 .compensate_exposure_bias = TRUE},
327
328 dt_gui_presets_update_ldr(_("scene-referred default"), self->op,
329 self->version(), FOR_RAW);
330}
331
332static void _deflicker_prepare_histogram(dt_iop_module_t *self, uint32_t **histogram,
333 dt_dev_histogram_stats_t *histogram_stats)
334{
336 dt_image_t image = *img;
338
339 if(image.dsc.channels != 1 || image.dsc.datatype != TYPE_UINT16) return;
340
343 DT_MIPMAP_BLOCKING, 'r');
344 if(IS_NULL_PTR(buf.buf))
345 {
346 dt_control_log(_("failed to get raw buffer from image `%s'"), image.filename);
348 return;
349 }
350
351 dt_dev_histogram_collection_params_t histogram_params = { 0 };
352
353 dt_histogram_roi_t histogram_roi = {.width = image.width,
354 .height = image.height,
355
356 // FIXME: get those from rawprepare IOP somehow !!!
357 .crop_x = image.crop_x,
358 .crop_y = image.crop_y,
359 .crop_width = image.crop_width,
360 .crop_height = image.crop_height };
361
362 histogram_params.roi = &histogram_roi;
363 histogram_params.bins_count = DEFLICKER_BINS_COUNT;
364
365 dt_histogram_worker(&histogram_params, histogram_stats, buf.buf, histogram,
367 histogram_stats->ch = 1u;
368
370}
371
372/* input: 0 - 65535 (valid range: from black level to white level) */
373/* output: -16 ... 0 */
374static double _raw_to_ev(uint32_t raw, uint32_t black_level, uint32_t white_level)
375{
376 const uint32_t raw_max = white_level - black_level;
377
378 // we are working on data without black clipping,
379 // so we can get values which are lower than the black level !!!
380 const int64_t raw_val = MAX((int64_t)raw - (int64_t)black_level, 1);
381
382 const double raw_ev = -log2(raw_max) + log2(raw_val);
383
384 return raw_ev;
385}
386
388 const dt_dev_pixelpipe_iop_t *piece,
389 const uint32_t *const histogram,
390 const dt_dev_histogram_stats_t *const histogram_stats, float *correction)
391{
392 const dt_iop_exposure_params_t *const p = (const dt_iop_exposure_params_t *const)p1;
393
394 *correction = NAN;
395
396 if(IS_NULL_PTR(histogram)) return;
397
398 const size_t total = (size_t)histogram_stats->ch * histogram_stats->pixels;
399
400 const double thr
401 = CLAMP(((double)total * (double)p->deflicker_percentile / (double)100.0), 0.0, (double)total);
402
403 size_t n = 0;
404 uint32_t raw = 0;
405
406 for(uint32_t i = 0; i < histogram_stats->bins_count; i++)
407 {
408 for(uint32_t k = 0; k < histogram_stats->ch; k++)
409 n += histogram[4 * i + k];
410
411 if((double)n >= thr)
412 {
413 raw = i;
414 break;
415 }
416 }
417
418 const double ev
419 = _raw_to_ev(raw, (uint32_t)piece->dsc_in.rawprepare.raw_black_level,
421
422 *correction = p->deflicker_target_level - ev;
423}
424
426 const dt_dev_pixelpipe_iop_t *piece)
427{
429 dt_iop_exposure_data_t *d = piece->data;
430
431 d->black = d->params.black;
432 float exposure = d->params.exposure;
433
434 if(d->deflicker)
435 {
436 if(!IS_NULL_PTR(g))
437 {
438 // histogram is precomputed and cached
439 _compute_correction(self, &d->params, piece, g->deflicker_histogram, &g->deflicker_histogram_stats,
440 &exposure);
441 }
442 else
443 {
444 uint32_t *histogram = NULL;
445 dt_dev_histogram_stats_t histogram_stats;
446 _deflicker_prepare_histogram(self, &histogram, &histogram_stats);
447 _compute_correction(self, &d->params, piece, histogram, &histogram_stats, &exposure);
448 dt_free(histogram);
449 }
450
451 // second, show computed correction in UI.
452 if(!IS_NULL_PTR(g) && dt_dev_pixelpipe_has_preview_output(self->dev, pipe, NULL))
453 {
455 g->deflicker_computed_exposure = exposure;
457 }
458 }
459
460 const float white = exposure2white(exposure);
461 d->scale = 1.0 / (white - d->black);
462}
463
464#ifdef HAVE_OPENCL
465int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
466{
467 const dt_iop_roi_t *const roi_in = &piece->roi_in;
470
471 cl_int err = -999;
472 const int devid = pipe->devid;
473 const int width = roi_in->width;
474 const int height = roi_in->height;
475
476 size_t sizes[] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid), 1 };
477 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 0, sizeof(cl_mem), (void *)&dev_in);
478 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 1, sizeof(cl_mem), (void *)&dev_out);
479 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 2, sizeof(int), (void *)&width);
480 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 3, sizeof(int), (void *)&height);
481 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 4, sizeof(float), (void *)&(d->black));
482 dt_opencl_set_kernel_arg(devid, gd->kernel_exposure, 5, sizeof(float), (void *)&(d->scale));
483 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_exposure, sizes);
484 if(err != CL_SUCCESS) goto error;
485
486 return TRUE;
487
488error:
489 dt_print(DT_DEBUG_OPENCL, "[opencl_exposure] couldn't enqueue kernel! %d\n", err);
490 return FALSE;
491}
492#endif
493
495int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
496{
497 const dt_iop_roi_t *const roi_out = &piece->roi_out;
498 const dt_iop_exposure_data_t *const d = (const dt_iop_exposure_data_t *const)piece->data;
499
500 const int ch = piece->dsc_in.channels;
501
502 const float *const restrict in = (float*)i;
503 float *const restrict out = (float*)o;
504 const float black = d->black;
505 const float scale = d->scale;
506 const size_t npixels = (size_t)roi_out->width * roi_out->height;
507 const gboolean use_stream = (ch == 4);
508
509 if(ch == 4)
510 {
511 const dt_aligned_pixel_simd_t black_v = dt_simd_set1(black);
512 const dt_aligned_pixel_simd_t scale_v = dt_simd_set1(scale);
514 for(size_t k = 0; k < npixels; k++)
515 {
516 const size_t p = 4 * k;
517 const dt_aligned_pixel_simd_t in_v = dt_load_simd_aligned(in + p);
518 dt_store_simd_nontemporal(out + p, (in_v - black_v) * scale_v);
519 }
520 }
521 else
522 {
523 __OMP_PARALLEL_FOR_SIMD__(aligned(in, out : 64))
524 for(size_t k = 0; k < ch * npixels; k++)
525 {
526 out[k] = (in[k] - black) * scale;
527 }
528 }
529
530 if(use_stream) dt_omploop_sfence(); // ensure streamed RGB writes complete before alpha copy touches output
531
533 dt_iop_alpha_copy(i, o, roi_out->width, roi_out->height);
534
535 return 0;
536}
537
538static float _get_exposure_bias(const struct dt_iop_module_t *self)
539{
540 float bias = 0.0f;
541
542 // just check that pointers exist and are initialized
543 if(self->dev && self->dev->image_storage.exif_exposure_bias)
545
546 // sanity checks, don't trust exif tags too much
547 if(!isnan(bias))
548 return CLAMP(bias, -5.0f, 5.0f);
549 else
550 return 0.0f;
551}
552
553void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
554{
555 const dt_iop_roi_t *const roi_out = &piece->roi_out;
557 if(piece->dsc_in.channels != 4) return;
558
559 const dt_iop_order_iccprofile_info_t *const input_profile = dt_ioppr_get_pipe_current_profile_info(self, pipe);
560 if(IS_NULL_PTR(input_profile)) return;
561
562 const float *const restrict in = (float*)i;
563 float average_luminance = 0.f;
564 const float norm = 1.f / (float)(roi_out->width * roi_out->height);
565
566 __OMP_PARALLEL_FOR__(reduction(+:average_luminance))
567 for(size_t k = 0; k < roi_out->width * roi_out->height * 4; k += 4)
568 {
569 // Convert each input RGB sample to XYZ to average scene luminance in a profile-aware way.
570 dt_aligned_pixel_t XYZ = { 0.f };
571 dt_ioppr_rgb_matrix_to_xyz(in + k, XYZ, input_profile->matrix_in_transposed, input_profile->lut_in,
572 input_profile->unbounded_coeffs_in, input_profile->lutsize,
573 input_profile->nonlinearlut);
574 average_luminance += XYZ[1] * norm;
575 }
576
577 // Solve the exposure module transfer so the average input luminance lands on middle grey at the output.
578 const float target_lightness = dt_conf_get_float("darkroom/modules/exposure/lightness");
579 const dt_aligned_pixel_t Lab = { target_lightness, 0.f, 0.f, 0.f };
580 dt_aligned_pixel_t XYZ = { 0.f };
582 const float target_luminance = XYZ[1];
583 const float white = p->black + fmaxf(average_luminance - p->black, 1e-6f) / target_luminance;
584 const float exposure = white2exposure(white);
585
586 p->exposure = exposure;
587
588 if(p->compensate_exposure_bias)
589 p->exposure += _get_exposure_bias(self);
590}
591
592
595{
598
599 d->params.black = p->black;
600 d->params.exposure = p->exposure;
601 d->params.deflicker_percentile = p->deflicker_percentile;
602 d->params.deflicker_target_level = p->deflicker_target_level;
603
604 // If exposure bias compensation has been required, add it on top of user exposure correction
605 if(p->compensate_exposure_bias)
606 d->params.exposure -= _get_exposure_bias(self);
607
608 d->deflicker = 0;
609
610 if(p->mode == EXPOSURE_MODE_DEFLICKER
612 && self->dev->image_storage.dsc.channels == 1
614 {
615 d->deflicker = 1;
616 }
617 dt_iop_fmt_log(self, "commit: class=%s needs_rawprepare=%d channels=%i datatype=%i mode=%d -> deflicker=%d",
621 p->mode, d->deflicker);
622
623 _process_common_setup(self, pipe, piece);
624 for(int k = 0; k < 3; k++) piece->dsc_out.processed_maximum[k] = piece->dsc_in.processed_maximum[k] * d->scale;
625}
626
628{
630 piece->data_size = sizeof(dt_iop_exposure_data_t);
631}
632
634{
635 dt_free_align(piece->data);
636 piece->data = NULL;
637}
638
640{
642}
643
644void gui_update(struct dt_iop_module_t *self)
645{
648
650 || self->dev->image_storage.dsc.channels != 1
652 {
653 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), FALSE);
654 }
655 else
656 {
657 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), TRUE);
658 }
659
661
662 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->compensate_exposure_bias), p->compensate_exposure_bias);
663 /* xgettext:no-c-format */
664 gchar *label = g_strdup_printf(_("compensate camera exposure (%+.1f EV)"), _get_exposure_bias(self));
665 gtk_button_set_label(GTK_BUTTON(g->compensate_exposure_bias), label);
666 gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->compensate_exposure_bias))), PANGO_ELLIPSIZE_MIDDLE);
667 dt_free(label);
668
669 g->spot_RGB[0] = 0.f;
670 g->spot_RGB[1] = 0.f;
671 g->spot_RGB[2] = 0.f;
672 g->spot_RGB[3] = 0.f;
673
674 // get the saved params
676
677 const float lightness = dt_conf_get_float("darkroom/modules/exposure/lightness");
678 dt_bauhaus_slider_set(g->lightness_spot, lightness);
679
681
682 dt_free(g->deflicker_histogram);
683
684 gtk_label_set_text(g->deflicker_used_EC, "");
686 g->deflicker_computed_exposure = NAN;
688
689 switch(p->mode)
690 {
692 _autoexp_disable(self);
693 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker");
694 _deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats);
695 break;
697 default:
698 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual");
699 break;
700 }
701
703}
704
706{
707 const int program = 2; // from programs.conf: basic.cl
710 module->data = gd;
711 gd->kernel_exposure = dt_opencl_create_kernel(program, "exposure");
712}
713
720
721static void _exposure_set_white(struct dt_iop_module_t *self, const float white)
722{
724
725 const float exposure = white2exposure(white);
726 if(p->exposure == exposure) return;
727
728 p->exposure = exposure;
729 if(p->black >= white) _exposure_set_black(self, white - 0.01);
730
732
734 dt_bauhaus_slider_set(g->exposure, p->exposure);
737}
738
739static void _exposure_set_black(struct dt_iop_module_t *self, const float black)
740{
742
743 if(p->black == black) return;
744
745 p->black = black;
746 if(p->black >= exposure2white(p->exposure))
747 {
748 _exposure_set_white(self, p->black + 0.01);
749 }
750
753 dt_bauhaus_slider_set(g->black, p->black);
756}
757
759{
762
763 // capture gui color picked event.
764 if(self->picked_color_max[0] < self->picked_color_min[0])
765 {
766 dt_print(DT_DEBUG_DEV, "[picker/exposure] rejected invalid min/max min=%g max=%g\n",
767 self->picked_color_min[0], self->picked_color_max[0]);
768 return;
769 }
770 const float *RGB = self->picked_color;
771 dt_print(DT_DEBUG_DEV, "[picker/exposure] RGB=(%g,%g,%g) pipe=%p\n",
772 RGB[0], RGB[1], RGB[2], (void *)pipe);
773
774 // Get the profile of whatever colorspace the picked sample actually lives in: exposure's
775 // iop-order is user-configurable, so its input can be raw camera RGB (before colorin) or
776 // already-managed RGB (if reordered after colorin) -- see dt_ioppr_get_pipe_current_profile_info.
777 const dt_iop_order_iccprofile_info_t *const input_profile = dt_ioppr_get_pipe_current_profile_info(self, pipe);
778 if(IS_NULL_PTR(input_profile))
779 {
780 dt_print(DT_DEBUG_DEV, "[picker/exposure] missing input profile\n");
781 return;
782 }
783
784 // Convert to XYZ. Some profiles (e.g. camera input profiles with a parametric TRC, or a
785 // non-linear work profile) need their input curve applied before the matrix -- a bare
786 // dot_product against matrix_in would silently skip that curve and produce garbage XYZ
787 // for any such profile. dt_ioppr_rgb_matrix_to_xyz (same helper autoset() above uses) applies
788 // the curve first whenever profile_info->nonlinearlut says it's needed.
791 dt_ioppr_rgb_matrix_to_xyz(RGB, XYZ, input_profile->matrix_in_transposed, input_profile->lut_in,
792 input_profile->unbounded_coeffs_in, input_profile->lutsize,
793 input_profile->nonlinearlut);
795 Lab[1] = Lab[2] = 0.f; // make color grey to get only the equivalent lighness
797 dt_XYZ_to_sRGB(XYZ, g->spot_RGB);
798
799 // Convert to Lch for GUI feedback (input)
801 dt_Lab_2_LCH(Lab, Lch);
802
803 // Write report in GUI
805 gtk_label_set_text(GTK_LABEL(g->Lch_origin),
806 g_strdup_printf(_("L : \t%.1f %%"), Lch[0]));
807 gtk_widget_queue_draw(g->origin_spot);
809
810 const dt_spot_mode_t mode = dt_bauhaus_combobox_get(g->spot_mode);
811
812 if(mode == DT_SPOT_MODE_MEASURE)
813 {
814 // get the exposure setting
815 float expo = p->exposure;
816
817 // If the exposure bias compensation is on, we need to add it to the user param
818 if(p->compensate_exposure_bias)
819 expo -= _get_exposure_bias(self);
820
821 const float white = exposure2white(-expo);
822
823 // apply the exposure compensation
824 dt_aligned_pixel_t XYZ_out;
825 for(int c = 0; c < 3; c++)
826 XYZ_out[c] = XYZ[c] * white;
827
828 // Convert to Lab for GUI feedback
829 dt_aligned_pixel_t Lab_out;
830 dt_XYZ_to_Lab(XYZ_out, Lab_out);
831 Lab_out[1] = Lab_out[2] = 0.f; // make it grey
832
833 // Return the values in sliders
835 dt_bauhaus_slider_set(g->lightness_spot, Lab_out[0]);
836 _paint_hue(self);
838
839 dt_conf_set_float("darkroom/modules/exposure/lightness", Lab_out[0]);
840 }
841 else if(mode == DT_SPOT_MODE_CORRECT)
842 {
843 // Get the target color in XYZ space
844 dt_aligned_pixel_t Lch_target = { 0.f };
846 Lch_target[0] = dt_bauhaus_slider_get(g->lightness_spot);
848
849 dt_aligned_pixel_t Lab_target = { 0.f };
850 dt_LCH_2_Lab(Lch_target, Lab_target);
851
852 dt_aligned_pixel_t XYZ_target = { 0.f };
853 dt_Lab_to_XYZ(Lab_target, XYZ_target);
854
855 // Get the ratio
856 float white = XYZ[1] / XYZ_target[1];
857 float expo = -white2exposure(white);
858
859 // If the exposure bias compensation is on, we need to subtract it from the user param
860 if(p->compensate_exposure_bias)
861 expo -= _get_exposure_bias(self);
862
863 white = exposure2white(-expo);
864 _exposure_set_white(self, white);
865 }
866}
867
868
870{
871 (void)picker;
872 (void)piece;
873 if(dt_gui_widgets_suppressed()) return;
874 dt_print(DT_DEBUG_DEV, "[picker/exposure] apply picker=%p pipe=%p\n", (void *)picker, (void *)pipe);
875 _auto_set_exposure(self, pipe);
876}
877
878
879void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
880{
883
884 if(w == g->mode)
885 {
886 dt_free(g->deflicker_histogram);
887
888 /* The exposure picker lives on the "manual" stack page. Switching mode can hide
889 that page while the picker stays active, sampling/drawing on the image for a
890 control the user can no longer see or turn off from this widget. */
892
893 switch(p->mode)
894 {
896 _autoexp_disable(self);
898 || self->dev->image_storage.dsc.channels != 1
900 {
901 p->mode = EXPOSURE_MODE_MANUAL;
902 dt_bauhaus_combobox_set(g->mode, p->mode);
903 gtk_widget_set_sensitive(GTK_WIDGET(g->mode), FALSE);
904 break;
905 }
906 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker");
907 _deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats);
908 break;
910 default:
911 gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual");
912 break;
913 }
914 }
915 else if(w == g->exposure)
916 {
917 const float white = exposure2white(p->exposure);
918 if(p->black >= white)
919 _exposure_set_black(self, white - 0.01);
920 }
921 else if(w == g->black)
922 {
923 const float white = exposure2white(p->exposure);
924 if(p->black >= white)
925 _exposure_set_white(self, p->black + 0.01);
926 }
927}
928
929
930static gboolean _draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
931{
932 if(dt_gui_widgets_suppressed()) return FALSE;
933
935
937 if(!isnan(g->deflicker_computed_exposure))
938 {
939 gchar *str = g_strdup_printf(_("%.2f EV"), g->deflicker_computed_exposure);
940
942 gtk_label_set_text(g->deflicker_used_EC, str);
944
945 dt_free(str);
946 }
948 return FALSE;
949}
950
951
952static gboolean _target_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
953{
954 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
956
957 // Init
958 GtkAllocation allocation;
959 gtk_widget_get_allocation(widget, &allocation);
960 int width = allocation.width, height = allocation.height;
961 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
962 cairo_t *cr = cairo_create(cst);
963
964 // Margins
965 const float margin = 2. * DT_PIXEL_APPLY_DPI(1.5);
967 height -= 2 * margin;
968
969 // Paint target color
970 dt_aligned_pixel_t RGB = { 0 };
971 dt_aligned_pixel_t Lch = { 0 };
972 dt_aligned_pixel_t Lab = { 0 };
973 dt_aligned_pixel_t XYZ = { 0 };
974 Lch[0] = dt_bauhaus_slider_get(g->lightness_spot);
975 Lch[1] = 0.f;
976 Lch[2] = 0.f;
977 dt_LCH_2_Lab(Lch, Lab);
980
981 cairo_set_source_rgb(cr, RGB[0], RGB[1], RGB[2]);
982 cairo_rectangle(cr, INNER_PADDING, margin, width, height);
983 cairo_fill(cr);
984
985 // Clean
986 cairo_stroke(cr);
987 cairo_destroy(cr);
988 cairo_set_source_surface(crf, cst, 0, 0);
989 cairo_paint(crf);
990 cairo_surface_destroy(cst);
991 return TRUE;
992}
993
994
995static gboolean _origin_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
996{
997 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
999
1000 // Init
1001 GtkAllocation allocation;
1002 gtk_widget_get_allocation(widget, &allocation);
1003 int width = allocation.width;
1004 int height = allocation.height;
1005 cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
1006 cairo_t *cr = cairo_create(cst);
1007
1008 // Margins
1009 const float margin = 2. * DT_PIXEL_APPLY_DPI(1.5);
1011 height -= 2 * margin;
1012
1013 cairo_set_source_rgb(cr, g->spot_RGB[0], g->spot_RGB[1], g->spot_RGB[2]);
1014 cairo_rectangle(cr, INNER_PADDING, margin, width, height);
1015 cairo_fill(cr);
1016
1017 // Clean
1018 cairo_stroke(cr);
1019 cairo_destroy(cr);
1020 cairo_set_source_surface(crf, cst, 0, 0);
1021 cairo_paint(crf);
1022 cairo_surface_destroy(cst);
1023 return TRUE;
1024}
1025
1026static void _paint_hue(dt_iop_module_t *self)
1027{
1028 // update the fill background color of LCh sliders
1030
1031 const float lightness_min = dt_bauhaus_slider_get_hard_min(g->lightness_spot);
1032 const float lightness_max = dt_bauhaus_slider_get_hard_max(g->lightness_spot);
1033
1034 const float lightness_range = lightness_max - lightness_min;
1035
1036 for(int i = 0; i < DT_BAUHAUS_SLIDER_MAX_STOPS; i++)
1037 {
1038 const float stop = ((float)i / (float)(DT_BAUHAUS_SLIDER_MAX_STOPS - 1));
1039 const float x = lightness_min + stop * lightness_range;
1040 dt_aligned_pixel_t RGB = { 0 };
1041 const dt_aligned_pixel_t Lch = { x, 0.f, 0. };
1042 dt_aligned_pixel_t Lab = { 0 };
1043 dt_aligned_pixel_t XYZ = { 0 };
1044
1045 dt_LCH_2_Lab(Lch, Lab);
1048
1049 dt_bauhaus_slider_set_stop(g->lightness_spot, stop, RGB[0], RGB[1], RGB[2]);
1050 }
1051
1052 gtk_widget_queue_draw(g->lightness_spot);
1053 gtk_widget_queue_draw(g->target_spot);
1054}
1055
1056
1058{
1059 if(dt_gui_widgets_suppressed()) return;
1060
1062
1063 dt_aligned_pixel_t Lch_target = { 0.f };
1064
1065 Lch_target[0] = dt_bauhaus_slider_get(g->lightness_spot);
1066
1067 // Save the color on change
1068 dt_conf_set_float("darkroom/modules/exposure/lightness", Lch_target[0]);
1069
1071 _paint_hue(self);
1073
1074 // Re-run auto compute only for the module that currently owns the active picker.
1075 const dt_spot_mode_t mode = dt_bauhaus_combobox_get(g->spot_mode);
1076 const gboolean picker_active = dt_iop_color_picker_is_active_module(self);
1077 if(mode == DT_SPOT_MODE_CORRECT && picker_active)
1078 _auto_set_exposure(self, self->dev->pipe);
1079 // else : just record new values and do nothing
1080}
1081
1082void gui_reset(struct dt_iop_module_t *self)
1083{
1085}
1086
1087void gui_init(struct dt_iop_module_t *self)
1088{
1090
1091 g->deflicker_histogram = NULL;
1092
1093 // Start building top level widget
1094 // Note: stupid dt_bauhaus_toggle/combobox/slider_from_params read self directly
1095 // and are hard-coded to pack_start widgets to self->widget.
1096 // So we need to store the main widget first, stupidly update the ref to self->widget,
1097 // as we add boxes and restore it last to the main widget.
1098 // The guy who thought of that should really burn his computer and do everyone a favour.
1099 GtkWidget *main_widget = self->widget = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING));
1100
1101 g->mode = dt_bauhaus_combobox_from_params(self, N_("mode"));
1102
1103 g->mode_stack = GTK_STACK(gtk_stack_new());
1104 gtk_stack_set_homogeneous(GTK_STACK(g->mode_stack),FALSE);
1105 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(g->mode_stack), TRUE, TRUE, 0);
1106
1107 GtkWidget *vbox_manual = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1108 gtk_stack_add_named(GTK_STACK(g->mode_stack), vbox_manual, "manual");
1109
1110 g->compensate_exposure_bias = dt_bauhaus_toggle_from_params(self, "compensate_exposure_bias");
1111 gtk_widget_set_tooltip_text(g->compensate_exposure_bias, _("automatically remove the camera exposure bias\n"
1112 "this is useful if you exposed the image to the right."));
1113
1114 g->exposure = dt_color_picker_new(self, DT_COLOR_PICKER_AREA,
1115 dt_bauhaus_slider_from_params(self, N_("exposure")));
1116 gtk_widget_set_tooltip_text(g->exposure, _("adjust the exposure correction"));
1117 dt_bauhaus_slider_set_digits(g->exposure, 3);
1118 dt_bauhaus_slider_set_format(g->exposure, _(" EV"));
1119 dt_bauhaus_slider_set_soft_range(g->exposure, -3.0, 4.0);
1120
1121 g->black = dt_bauhaus_slider_from_params(self, "black");
1122 gtk_widget_set_tooltip_text(g->black, _("adjust the black level to unclip negative RGB values.\n"
1123 "you should never use it to add more density in blacks!\n"
1124 "if poorly set, it will clip near-black colors out of gamut\n"
1125 "by pushing RGB values into negatives."));
1127 dt_bauhaus_slider_set_soft_range(g->black, -0.1, 0.1);
1128
1129 GtkWidget *vbox_deflicker = self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1130 gtk_stack_add_named(GTK_STACK(g->mode_stack), vbox_deflicker, "deflicker");
1131
1132 g->deflicker_percentile = dt_bauhaus_slider_from_params(self, "deflicker_percentile");
1133 dt_bauhaus_slider_set_format(g->deflicker_percentile, "%");
1134 gtk_widget_set_tooltip_text(g->deflicker_percentile,
1135 // xgettext:no-c-format
1136 _("where in the histogram to meter for deflicking. E.g. 50% is median"));
1137
1138 g->deflicker_target_level = dt_bauhaus_slider_from_params(self, "deflicker_target_level");
1139 dt_bauhaus_slider_set_format(g->deflicker_target_level, _(" EV"));
1140 gtk_widget_set_tooltip_text(g->deflicker_target_level,
1141 _("where to place the exposure level for processed pics, EV below overexposure."));
1142
1143 GtkBox *hbox1 = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
1144 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(dt_ui_label_new(_("computed EC: "))), FALSE, FALSE, 0);
1145 g->deflicker_used_EC = GTK_LABEL(dt_ui_label_new("")); // This gets filled in by process
1146 gtk_widget_set_tooltip_text(GTK_WIDGET(g->deflicker_used_EC), _("what exposure correction has actually been used"));
1147 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(g->deflicker_used_EC), FALSE, FALSE, 0);
1148
1150 g->deflicker_computed_exposure = NAN;
1152
1153 self->widget = main_widget;
1154
1156 (&g->cs,
1157 "plugins/darkroom/exposure/mapping",
1158 _("spot exposure mapping"),
1159 GTK_BOX(self->widget), GTK_PACK_END);
1160
1161 DT_BAUHAUS_COMBOBOX_NEW_FULL(darktable.bauhaus, g->spot_mode, DT_GUI_MODULE(self), N_("spot mode"),
1162 _("\"correction\" automatically adjust exposure\n"
1163 "such that the input lightness is mapped to the target.\n"
1164 "\"measure\" simply shows how an input color is mapped by the exposure compensation\n"
1165 "and can be used to define a target."),
1166 0, NULL, self,
1167 N_("correction"),
1168 N_("measure"));
1169 gtk_box_pack_start(GTK_BOX(g->cs.container), GTK_WIDGET(g->spot_mode), TRUE, TRUE, 0);
1170 g_signal_connect(G_OBJECT(g->spot_mode), "value-changed", G_CALLBACK(_spot_settings_changed_callback), self);
1171
1172 GtkWidget *hhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1173 GtkWidget *vvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1174
1175 gtk_box_pack_start(GTK_BOX(vvbox), dt_ui_section_label_new(_("input")), FALSE, FALSE, 0);
1176
1177 g->origin_spot = GTK_WIDGET(gtk_drawing_area_new());
1178 gtk_widget_set_size_request(g->origin_spot, 2 * DT_PIXEL_APPLY_DPI(darktable.bauhaus->quad_width),
1180 gtk_widget_set_tooltip_text(GTK_WIDGET(g->origin_spot),
1181 _("the input color that should be mapped to the target"));
1182
1183 g_signal_connect(G_OBJECT(g->origin_spot), "draw", G_CALLBACK(_origin_color_draw), self);
1184 gtk_box_pack_start(GTK_BOX(vvbox), g->origin_spot, TRUE, TRUE, 0);
1185
1186 g->Lch_origin = gtk_label_new(_("L : \tN/A"));
1187 gtk_widget_set_tooltip_text(GTK_WIDGET(g->Lch_origin),
1188 _("these LCh coordinates are computed from CIE Lab 1976 coordinates"));
1189 gtk_box_pack_start(GTK_BOX(vvbox), GTK_WIDGET(g->Lch_origin), FALSE, FALSE, 0);
1190
1191 gtk_box_pack_start(GTK_BOX(hhbox), GTK_WIDGET(vvbox), FALSE, FALSE, DT_BAUHAUS_SPACE);
1192
1193 vvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1194
1195 gtk_box_pack_start(GTK_BOX(vvbox), dt_ui_section_label_new(_("target")), FALSE, TRUE, 0);
1196
1197 g->target_spot = GTK_WIDGET(gtk_drawing_area_new());
1198 gtk_widget_set_size_request(g->target_spot, 2 * DT_PIXEL_APPLY_DPI(darktable.bauhaus->quad_width),
1200 gtk_widget_set_tooltip_text(GTK_WIDGET(g->target_spot),
1201 _("the desired target exposure after mapping"));
1202
1203 g_signal_connect(G_OBJECT(g->target_spot), "draw", G_CALLBACK(_target_color_draw), self);
1204 gtk_box_pack_start(GTK_BOX(vvbox), g->target_spot, TRUE, TRUE, 0);
1205
1206 g->lightness_spot = dt_bauhaus_slider_new_with_range(darktable.bauhaus, DT_GUI_MODULE(self), 0., 100., 0, 0, 1);
1207 dt_bauhaus_widget_set_label(g->lightness_spot, N_("lightness"));
1208 dt_bauhaus_slider_set_format(g->lightness_spot, "%");
1209 dt_bauhaus_slider_set_default(g->lightness_spot, 50.f);
1210 gtk_box_pack_start(GTK_BOX(vvbox), GTK_WIDGET(g->lightness_spot), TRUE, TRUE, 0);
1211 g_signal_connect(G_OBJECT(g->lightness_spot), "value-changed", G_CALLBACK(_spot_settings_changed_callback), self);
1212
1213 gtk_box_pack_start(GTK_BOX(hhbox), GTK_WIDGET(vvbox), TRUE, TRUE, DT_BAUHAUS_SPACE);
1214
1215 gtk_box_pack_start(GTK_BOX(g->cs.container), GTK_WIDGET(hhbox), FALSE, FALSE, 0);
1216
1217 g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_draw), self);
1218}
1219
1221{
1223
1224 dt_free(g->deflicker_histogram);
1225
1227}
1228
1229// clang-format off
1230// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1231// vim: shiftwidth=2 expandtab tabstop=2 cindent
1232// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1233// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
Definition bauhaus.c:1650
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3549
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
Definition bauhaus.c:1643
void dt_bauhaus_slider_set_stop(GtkWidget *widget, float stop, float r, float g, float b)
Definition bauhaus.c:2375
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3486
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2350
float dt_bauhaus_slider_get_hard_min(GtkWidget *widget)
Definition bauhaus.c:1577
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3537
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2304
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1656
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
Definition bauhaus.c:1783
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3613
float dt_bauhaus_slider_get_hard_max(GtkWidget *widget)
Definition bauhaus.c:1602
#define DT_BAUHAUS_SPACE
Definition bauhaus.h:291
#define INTERNAL_PADDING
Definition bauhaus.h:76
#define DT_BAUHAUS_COMBOBOX_NEW_FULL(bauhaus, widget, action, label, tip, pos, callback, data,...)
Definition bauhaus.h:392
#define DT_BAUHAUS_SLIDER_MAX_STOPS
Definition bauhaus.h:71
#define INNER_PADDING
Definition bauhaus.h:79
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ DEVELOP_BLEND_CS_RGB_SCENE
Definition blend.h:60
@ DEVELOP_BLEND_CS_RGB_DISPLAY
Definition blend.h:59
dt_spot_mode_t
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
@ IOP_CS_RGB
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
gboolean dt_iop_color_picker_is_active_module(const dt_iop_module_t *module)
Tell whether one module currently owns the active darkroom picker.
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
@ DT_COLOR_PICKER_AREA
dt_Lab_to_XYZ(Lab, XYZ)
dt_XYZ_to_sRGB(XYZ, result)
static dt_aligned_pixel_t XYZ
static dt_aligned_pixel_t Lab
const dt_colormatrix_t dt_aligned_pixel_t out
dt_XYZ_to_Lab(XYZ, Lab)
static dt_aligned_pixel_t RGB
static dt_aligned_pixel_t Lch
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_histogram_worker(dt_dev_histogram_collection_params_t *const histogram_params, dt_dev_histogram_stats_t *histogram_stats, const void *const pixel, uint32_t **histogram, const dt_worker Worker, const dt_iop_order_iccprofile_info_t *const profile_info)
void dt_histogram_helper_cs_RAW_uint16(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
gboolean dt_image_needs_rawprepare(const dt_image_t *img)
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:777
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
#define dt_free_align(ptr)
Definition darktable.h:503
static void * dt_calloc_align(size_t size)
Definition darktable.h:510
@ DT_DEBUG_OPENCL
Definition darktable.h:744
@ DT_DEBUG_DEV
Definition darktable.h:739
#define dt_gui_freeze_begin()
Definition darktable.h:900
#define dt_gui_freeze_end()
Definition darktable.h:901
#define dt_free(ptr)
Definition darktable.h:478
void void void gboolean dt_gui_widgets_suppressed(void)
Definition gtk.c:194
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __DT_CLONE_TARGETS__
Definition darktable.h:379
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:270
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:271
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:293
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:42
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
Definition develop.c:414
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
static float _get_exposure_bias(const struct dt_iop_module_t *self)
Definition exposure.c:538
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)
Definition exposure.c:593
static gboolean _draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
Definition exposure.c:930
const char ** description(struct dt_iop_module_t *self)
Definition exposure.c:162
int default_group()
Definition exposure.c:173
static void _spot_settings_changed_callback(GtkWidget *slider, dt_iop_module_t *self)
Definition exposure.c:1057
static gboolean _origin_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition exposure.c:995
#define DEFLICKER_BINS_COUNT
Definition exposure.c:106
static double _raw_to_ev(uint32_t raw, uint32_t black_level, uint32_t white_level)
Definition exposure.c:374
#define exposure2white(x)
Definition exposure.c:86
dt_spot_mode_t
Definition exposure.c:98
@ DT_SPOT_MODE_MEASURE
Definition exposure.c:100
@ DT_SPOT_MODE_CORRECT
Definition exposure.c:99
@ DT_SPOT_MODE_LAST
Definition exposure.c:101
static void _auto_set_exposure(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe)
Definition exposure.c:758
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:627
const char * name()
Definition exposure.c:157
static void _exposure_set_black(struct dt_iop_module_t *self, const float black)
Definition exposure.c:739
void output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition exposure.c:191
void gui_reset(struct dt_iop_module_t *self)
Definition exposure.c:1082
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition exposure.c:644
static void _exposure_set_white(struct dt_iop_module_t *self, const float white)
Definition exposure.c:721
void gui_init(struct dt_iop_module_t *self)
Definition exposure.c:1087
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition exposure.c:879
static void _autoexp_disable(dt_iop_module_t *self)
Definition exposure.c:639
#define white2exposure(x)
Definition exposure.c:87
void cleanup_global(dt_iop_module_so_t *module)
Definition exposure.c:714
static void _compute_correction(dt_iop_module_t *self, dt_iop_params_t *p1, const dt_dev_pixelpipe_iop_t *piece, const uint32_t *const histogram, const dt_dev_histogram_stats_t *const histogram_stats, float *correction)
Definition exposure.c:387
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:183
int flags()
Definition exposure.c:178
static void _process_common_setup(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:425
void gui_cleanup(struct dt_iop_module_t *self)
Definition exposure.c:1220
void init_presets(dt_iop_module_so_t *self)
Definition exposure.c:303
static void _deflicker_prepare_histogram(dt_iop_module_t *self, uint32_t **histogram, dt_dev_histogram_stats_t *histogram_stats)
Definition exposure.c:332
__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 i, void *const o)
Definition exposure.c:495
static void _paint_hue(dt_iop_module_t *self)
Definition exposure.c:1026
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:633
void init_global(dt_iop_module_so_t *module)
Definition exposure.c:705
dt_iop_exposure_mode_t
Definition exposure.c:92
@ EXPOSURE_MODE_MANUAL
Definition exposure.c:93
@ EXPOSURE_MODE_DEFLICKER
Definition exposure.c:94
void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
Definition exposure.c:553
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
Definition exposure.c:465
static gboolean _target_color_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
Definition exposure.c:952
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition exposure.c:869
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
Definition exposure.c:200
void default_output_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
Definition format.c:75
@ TYPE_UINT16
Definition format.h:47
void dt_gui_new_collapsible_section(dt_gui_collapsible_section_t *cs, const char *confname, const char *label, GtkBox *parent, GtkPackType pack)
Create a collapsible section and pack it into the parent box.
Definition gtk.c:3334
void dt_gui_update_collapsible_section(dt_gui_collapsible_section_t *cs)
Definition gtk.c:3312
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
Definition gtk.h:322
static GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition gtk.h:469
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
static GtkWidget * dt_ui_label_new(const gchar *str)
Definition gtk.h:479
void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version, const int ldrflag)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
@ FOR_RAW
Definition gui/presets.h:41
#define DT_GUI_MODULE(x)
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
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)
Definition imageop.c:3220
#define dt_omploop_sfence()
Definition imageop.h:747
#define IOP_GUI_FREE
Definition imageop.h:641
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
Definition imageop.h:450
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
Definition imageop.h:490
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:197
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:199
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
Definition imageop.h:456
@ IOP_GROUP_TONES
Definition imageop.h:167
#define IOP_GUI_ALLOC(module)
Definition imageop.h:638
GtkWidget * dt_bauhaus_toggle_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
static const float x
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define dt_mipmap_cache_get(A, B, C, D, E, F)
@ DT_MIPMAP_BLOCKING
#define dt_mipmap_cache_release(A, B)
@ DT_MIPMAP_FULL
float dt_aligned_pixel_t[4]
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2164
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2058
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2101
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2155
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:804
struct dt_bauhaus_t * bauhaus
Definition darktable.h:806
struct dt_image_cache_t * image_cache
Definition darktable.h:805
struct dt_develop_t * develop
Definition darktable.h:798
float quad_width
Definition bauhaus.h:273
const struct dt_histogram_roi_t * roi
Definition pixelpipe.h:56
dt_iop_buffer_dsc_t dsc_out
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_image_t image_storage
Definition develop.h:259
struct dt_dev_pixelpipe_t * pipe
Definition develop.h:247
int32_t height
Definition image.h:315
float exif_exposure_bias
Definition image.h:286
int32_t crop_height
Definition image.h:316
int32_t width
Definition image.h:315
int32_t crop_y
Definition image.h:316
int32_t crop_x
Definition image.h:316
dt_iop_buffer_dsc_t dsc
Definition image.h:337
int32_t crop_width
Definition image.h:316
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
int32_t id
Definition image.h:319
uint16_t raw_black_level
Definition format.h:74
unsigned int channels
Definition format.h:54
struct dt_iop_buffer_dsc_t::@32 rawprepare
dt_iop_buffer_type_t datatype
Definition format.h:56
dt_aligned_pixel_t processed_maximum
Definition format.h:85
uint16_t raw_white_point
Definition format.h:75
dt_iop_exposure_params_t params
Definition exposure.c:145
GtkWidget * compensate_exposure_bias
Definition exposure.c:129
GtkWidget * deflicker_percentile
Definition exposure.c:124
dt_gui_collapsible_section_t cs
Definition exposure.c:137
dt_dev_histogram_stats_t deflicker_histogram_stats
Definition exposure.c:127
uint32_t * deflicker_histogram
Definition exposure.c:126
dt_aligned_pixel_t spot_RGB
Definition exposure.c:139
GtkWidget * deflicker_target_level
Definition exposure.c:125
dt_iop_exposure_mode_t mode
Definition exposure.c:110
gboolean compensate_exposure_bias
Definition exposure.c:115
GModule *dt_dev_operation_t op
Definition imageop.h:260
dt_iop_global_data_t * data
Definition imageop.h:263
dt_iop_params_t * default_params
Definition imageop.h:344
GtkWidget * widget
Definition imageop.h:374
struct dt_develop_t * dev
Definition imageop.h:333
dt_iop_gui_data_t * gui_data
Definition imageop.h:348
dt_iop_global_data_t * global_data
Definition imageop.h:351
dt_aligned_pixel_t picked_color_min
Definition imageop.h:309
dt_aligned_pixel_t picked_color_max
Definition imageop.h:309
dt_aligned_pixel_t picked_color
Definition imageop.h:309
dt_iop_params_t * params
Definition imageop.h:344
dt_colormatrix_t matrix_in_transposed
Definition iop_profile.h:65
Region of interest passed through the pixelpipe.
Definition imageop.h:72
#define MAX(a, b)
Definition thinplate.c:29